1from typing import Iterable, Dict, Tuple, Set, List
2from quantum_launcher.import_management import DependencyError
3try:
4 from qiskit.quantum_info import SparsePauliOp
5except ImportError as e:
6 raise DependencyError(e, 'qiskit') from e
7
8
[docs]
9def qubo_to_hamiltonian(qubo: Iterable[Iterable[int]] | Dict[Tuple[str, str], float], offset: float = 0) -> SparsePauliOp:
10 """
11 Convert a QUBO into a quadratic Hamiltonian in the form of a SparsePauliOp.
12
13 Args:
14 qubo (Iterable[Iterable[int]] | Dict[Tuple[str, str], float]): Quadratic Unconstrained Binary Optimization written in the form of matrix or dictionary[Tuple[key, key], value].
15 offset (float, optional): The offset (constant) value that will be added to identity. Defaults to 0.
16
17 Returns:
18 SparsePauliOp: _description_
19 """
20
21 if isinstance(qubo, dict):
22 return _qubo_dict_into_hamiltonian(qubo, offset)
23 elif isinstance(qubo, Iterable):
24 return _qubo_matrix_into_hamiltonian(qubo, offset)
25 raise ValueError("QUBO must be a matrix or a dictionary")
26
27
28def _qubo_matrix_into_hamiltonian(qubo: Iterable[Iterable[int]], offset: float = 0) -> SparsePauliOp:
29 N = len(qubo)
30 assert all(len(row) == N for row in qubo), "QUBO matrix must be square"
31
32 sparse_list: List[Tuple[str, List, float]] = []
33 constant: float = offset
34 for ind_r, row in enumerate(qubo):
35 val = row[ind_r]
36 constant += val/2
37 sparse_list.append(('Z', [ind_r], -val / 2))
38 for ind_c, val in enumerate(row[ind_r + 1:], ind_r + 1):
39 if val != 0:
40 constant += val / 4
41 sparse_list.append(('Z', [ind_r], -val / 4))
42 sparse_list.append(('Z', [ind_c], -val / 4))
43 sparse_list.append(('ZZ', [ind_r, ind_c], val / 4))
44 hamiltonian: SparsePauliOp = SparsePauliOp.from_sparse_list(sparse_list, N)
45 hamiltonian += SparsePauliOp.from_sparse_list([('I', [0], constant)], N)
46 return hamiltonian.simplify()
47
48
49def _qubo_dict_into_hamiltonian(qubo: Dict[Tuple[str, str], float], offset: float = 0) -> SparsePauliOp:
50 label_set: Set[str] = set()
51 for (arg1, arg2) in sorted(qubo.keys()):
52 if arg1 not in label_set:
53 label_set.add(arg1)
54 if arg2 not in label_set:
55 label_set.add(arg2)
56
57 labels = {label: i for i, label in enumerate(sorted(label_set))}
58
59 N: int = len(labels)
60
61 sparse_list: List[Tuple[str, List, float]] = []
62 constant: float = offset
63 for (arg1, arg2), coeff in qubo.items():
64 if arg1 == arg2:
65 constant += coeff / 2
66 sparse_list.append(('Z', [labels[arg1]], -coeff / 2))
67 else:
68 constant += coeff / 4
69 sparse_list.append(('ZZ', [labels[arg1], labels[arg2]], coeff / 4))
70 sparse_list.append(('Z', [labels[arg1]], -coeff / 4))
71 sparse_list.append(('Z', [labels[arg2]], -coeff / 4))
72
73 hamiltonian = SparsePauliOp.from_sparse_list(sparse_list, N)
74 hamiltonian += SparsePauliOp.from_sparse_list([('I', [0], constant)], N)
75
76 return hamiltonian.simplify()