Skip to content

Commit fd1283c

Browse files
authored
Merge pull request #17 from simsaidan/aidanonefileonefunction
refactor: split core definitions into focused modules
2 parents 6907fda + e132755 commit fd1283c

49 files changed

Lines changed: 1141 additions & 828 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/simple_algo_benchmark.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,27 @@
99
if ROOT not in sys.path:
1010
sys.path.insert(0, ROOT)
1111

12-
from src.core.utils import (
12+
from src.utils.constants import (
1313
zero_state_two_qubits,
1414
one_state_two_qubits,
1515
two_state_two_qubits,
1616
three_state_two_qubits,
17-
tensor,
1817
I,
1918
)
19+
from src.utils.tensor import tensor
2020

2121
from src.benchmarking.benchmark import Benchmark
22-
from src.core.hamiltonian import LocalHamiltonian, Hamiltonian
22+
from src.core.hamiltonian import Hamiltonian
23+
from src.core.local_hamiltonian import LocalHamiltonian
2324
from src.simulators.qutip_simulator import QutipSimulator
2425
from src.simulators.splitjmatrix_simulator import (
2526
SplitJMatrixSimulator,
2627
_cavity_population,
2728
_population_one,
2829
)
30+
from src.core.local_operator import LocalOperator
31+
from src.core.operator import Operator
2932
from src.core.state import State
30-
from src.core.operator_set import LocalOperator, Operator
3133

3234
# Define system parameters
3335
omega_c = 245000

examples/simple_shadow.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import numpy as np
1111

1212
from src.core.hamiltonian import Hamiltonian
13-
from src.core.operator_set import Operator, OperatorSet
14-
from src.core.pauli import PauliString
13+
from src.core.operator import Operator
14+
from src.core.operator_set import OperatorSet
15+
from src.core.pauli_string import PauliString
1516
from src.simulators.qutip_simulator import QutipSimulator
1617
from src.core.state import State
1718
from src.shadow.shadow_hamiltonian import ShadowHamiltonian
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import numpy as np
2+
3+
from src.core.hamiltonian import Hamiltonian
4+
from src.core.local_hamiltonian import LocalHamiltonian
5+
6+
7+
def combined_hamiltonian_matrix(
8+
hamiltonians: list[Hamiltonian],
9+
num_qubits: int,
10+
) -> np.ndarray:
11+
"""
12+
Sum Hamiltonian terms on the full ``num_qubits``-site tensor space.
13+
14+
``LocalHamiltonian`` terms are embedded with identities on the remaining
15+
sites; full-domain ``Hamiltonian`` matrices are added as-is. All terms must
16+
match a common Hilbert-space dimension (``local_dim ** num_qubits`` for
17+
locals, or the matrix size of bare terms).
18+
19+
Parameter hamiltonians: The list of Hamiltonians to sum.
20+
Precondition: hamiltonians is a list of Hamiltonian objects.
21+
22+
Parameter num_qubits: The number of qubits in the full system.
23+
Precondition: num_qubits is a positive integer.
24+
"""
25+
assert isinstance(hamiltonians, list), "hamiltonians must be a list"
26+
assert all(
27+
isinstance(h, Hamiltonian) for h in hamiltonians
28+
), "all hamiltonians must be Hamiltonian objects"
29+
assert isinstance(num_qubits, int), "num_qubits must be an integer"
30+
assert num_qubits > 0, "num_qubits must be a positive integer"
31+
assert len(hamiltonians) > 0, "hamiltonians must be a non-empty list"
32+
33+
local_dims = {h.local_dim for h in hamiltonians if isinstance(h, LocalHamiltonian)}
34+
if len(local_dims) > 1:
35+
raise ValueError(
36+
f"mixed local_dim in LocalHamiltonian terms is not supported: {sorted(local_dims)}"
37+
)
38+
39+
target_dim: int | None = None
40+
for h in hamiltonians:
41+
if isinstance(h, LocalHamiltonian):
42+
d = h.local_dim**num_qubits
43+
else:
44+
d = int(np.asarray(h.matrix).shape[0])
45+
if target_dim is None:
46+
target_dim = d
47+
elif d != target_dim:
48+
raise ValueError(
49+
f"Hamiltonian dimensions disagree: got {d} vs {target_dim}"
50+
)
51+
52+
H_tot = np.zeros((target_dim, target_dim), dtype=np.complex128)
53+
for h in hamiltonians:
54+
if isinstance(h, LocalHamiltonian):
55+
ld = h.local_dim
56+
lo, hi = min(h.sites), max(h.sites)
57+
n_before = lo
58+
n_after = num_qubits - 1 - hi
59+
term = np.asarray(h.matrix, dtype=np.complex128)
60+
if n_before > 0:
61+
term = np.kron(np.eye(ld**n_before, dtype=np.complex128), term)
62+
if n_after > 0:
63+
term = np.kron(term, np.eye(ld**n_after, dtype=np.complex128))
64+
H_tot += term
65+
else:
66+
H_tot += np.asarray(h.matrix, dtype=np.complex128)
67+
return H_tot

src/core/hamiltonian.py

Lines changed: 35 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,62 @@
11
import numpy as np
22

3-
from src.core.operator_set import LocalOperator, Operator
3+
from src.core.operator import Operator
4+
from src.utils.hermitian import hermitian
45

56

67
class Hamiltonian(Operator):
8+
"""
9+
Represents a quantum Hamiltonian.
10+
The Hamiltonian must be Hermitian to be valid.
11+
"""
12+
713
def __init__(self, matrix: np.ndarray):
14+
"""Initializes a Hamiltonian object which represents a quantum
15+
Hamiltonian. The Hamtonian must be Hermitian to be valid.
16+
17+
Parameter matrix: The matrix representation of the Hamiltonian.
18+
Precondition: matrix is a numpy array.
19+
"""
20+
assert isinstance(matrix, np.ndarray), "matrix must be a numpy array"
21+
assert hermitian(matrix), "matrix must be Hermitian"
22+
assert (
23+
matrix.ndim == 2 and matrix.shape[0] == matrix.shape[1]
24+
), "matrix must be a square 2D array"
825
super().__init__(matrix)
926

1027
def __str__(self):
28+
"""Returns a string representation of the Hamiltonian."""
1129
return f"Hamiltonian(matrix={self.matrix})"
1230

1331
def __repr__(self):
32+
"""Returns a string representation of the Hamiltonian."""
1433
return f"Hamiltonian(matrix={self.matrix})"
1534

1635
def __eq__(self, other):
36+
"""Returns whether the Hamiltonian is equal to another Hamiltonian."""
1737
return np.allclose(self.matrix, other.matrix)
1838

1939
def __ne__(self, other):
40+
"""Returns whether the Hamiltonian is not equal to another Hamiltonian."""
2041
return not np.allclose(self.matrix, other.matrix)
2142

2243
def to_hamiltonian_set(self):
44+
"""Returns a HamiltonianSet containing the Hamiltonian."""
45+
from src.core.hamiltonian_set import HamiltonianSet
46+
2347
return HamiltonianSet([self])
2448

2549
def to_local_hamiltonian(self, local_dim: int = 2):
26-
lo = self.to_local_operator(local_dim)
27-
return LocalHamiltonian(lo.matrix, lo.sites, lo.local_dim)
28-
29-
30-
class LocalHamiltonian(LocalOperator, Hamiltonian):
31-
"""
32-
Local Hamiltonian acting non-trivially on the provided `sites`.
33-
34-
``sites`` must be distinct consecutive integers; see `LocalOperator`.
35-
"""
36-
37-
def __init__(
38-
self,
39-
matrix: np.ndarray,
40-
sites: list[int],
41-
local_dim: int = 2,
42-
):
43-
super().__init__(matrix, sites, local_dim)
44-
45-
def __str__(self):
46-
return (
47-
"LocalHamiltonian("
48-
f"sites={self.sites}, "
49-
f"local_dim={self.local_dim}, "
50-
f"shape={self.matrix.shape}"
51-
")"
52-
)
50+
"""Returns a LocalHamiltonian representing the Hamiltonian acting on
51+
the given sites.
5352
54-
def __repr__(self):
55-
return (
56-
"LocalHamiltonian("
57-
f"matrix={self.matrix!r}, "
58-
f"sites={self.sites!r}, "
59-
f"local_dim={self.local_dim}"
60-
")"
61-
)
62-
63-
64-
class HamiltonianSet:
65-
def __init__(self, hamiltonians: list[Hamiltonian]):
66-
self.hamiltonians = hamiltonians
67-
self.hamiltonian_count = len(hamiltonians)
68-
69-
def __str__(self):
70-
return f"HamiltonianSet(hamiltonian_count={self.hamiltonian_count})"
71-
72-
def __repr__(self):
73-
return f"HamiltonianSet(hamiltonians={self.hamiltonians!r})"
53+
Parameter local_dim: The local dimension of the Hamiltonian.
54+
Precondition: local_dim is a positive integer.
55+
"""
56+
assert isinstance(local_dim, int), "local_dim must be an integer"
57+
assert local_dim > 0, "local_dim must be a positive integer"
7458

59+
from src.core.local_hamiltonian import LocalHamiltonian
7560

76-
def combined_hamiltonian_matrix(
77-
hamiltonians: list[Hamiltonian],
78-
num_qubits: int,
79-
) -> np.ndarray:
80-
"""
81-
Sum Hamiltonian terms on the full ``num_qubits``-site tensor space.
82-
83-
``LocalHamiltonian`` terms are embedded with identities on the remaining
84-
sites; full-domain ``Hamiltonian`` matrices are added as-is. All terms must
85-
match a common Hilbert-space dimension (``local_dim ** num_qubits`` for
86-
locals, or the matrix size of bare terms).
87-
"""
88-
if not hamiltonians:
89-
raise ValueError("hamiltonians must be a non-empty list")
90-
91-
target_dim: int | None = None
92-
for h in hamiltonians:
93-
if isinstance(h, LocalHamiltonian):
94-
d = h.local_dim**num_qubits
95-
else:
96-
d = int(np.asarray(h.matrix).shape[0])
97-
if target_dim is None:
98-
target_dim = d
99-
elif d != target_dim:
100-
raise ValueError(
101-
f"Hamiltonian dimensions disagree: got {d} vs {target_dim}"
102-
)
103-
104-
H_tot = np.zeros((target_dim, target_dim), dtype=np.complex128)
105-
for h in hamiltonians:
106-
if isinstance(h, LocalHamiltonian):
107-
ld = h.local_dim
108-
lo, hi = min(h.sites), max(h.sites)
109-
n_before = lo
110-
n_after = num_qubits - 1 - hi
111-
term = np.asarray(h.matrix, dtype=np.complex128)
112-
if n_before > 0:
113-
term = np.kron(np.eye(ld**n_before, dtype=np.complex128), term)
114-
if n_after > 0:
115-
term = np.kron(term, np.eye(ld**n_after, dtype=np.complex128))
116-
H_tot += term
117-
else:
118-
H_tot += np.asarray(h.matrix, dtype=np.complex128)
119-
return H_tot
61+
lo = self.to_local_operator(local_dim)
62+
return LocalHamiltonian(lo.matrix, lo.sites, lo.local_dim)

src/core/hamiltonian_set.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from src.core.hamiltonian import Hamiltonian
2+
3+
4+
class HamiltonianSet:
5+
"""Represents a set of quantum Hamiltonians."""
6+
7+
def __init__(self, hamiltonians: list[Hamiltonian]):
8+
"""Initializes a HamiltonianSet object which represents a set of quantum
9+
Hamiltonians.
10+
11+
Parameter hamiltonians: The list of Hamiltonians to initialize the HamiltonianSet with.
12+
Precondition: hamiltonians is a list of Hamiltonian objects.
13+
"""
14+
assert isinstance(hamiltonians, list), "hamiltonians must be a list"
15+
assert all(
16+
isinstance(h, Hamiltonian) for h in hamiltonians
17+
), "all hamiltonians must be Hamiltonian objects"
18+
self.hamiltonians = hamiltonians
19+
self.hamiltonian_count = len(hamiltonians)
20+
21+
def __str__(self):
22+
"""Returns a string representation of the HamiltonianSet."""
23+
return f"HamiltonianSet(hamiltonian_count={self.hamiltonian_count})"
24+
25+
def __repr__(self):
26+
"""Returns a string representation of the HamiltonianSet."""
27+
return f"HamiltonianSet(hamiltonians={self.hamiltonians!r})"
28+
29+
def __iter__(self):
30+
"""Returns an iterator over the Hamiltonians in the HamiltonianSet."""
31+
return iter(self.hamiltonians)
32+
33+
def __len__(self):
34+
"""Returns the number of Hamiltonians in the HamiltonianSet."""
35+
return self.hamiltonian_count
36+
37+
def __getitem__(self, index: int):
38+
"""Returns the Hamiltonian at the given index."""
39+
return self.hamiltonians[index]
40+
41+
def __contains__(self, item: Hamiltonian):
42+
"""Returns whether the HamiltonianSet contains the given Hamiltonian."""
43+
return item in self.hamiltonians

0 commit comments

Comments
 (0)