diff --git a/check_my_spin.py b/check_my_spin.py new file mode 100644 index 0000000..b5f5437 --- /dev/null +++ b/check_my_spin.py @@ -0,0 +1,16 @@ +from moha.hamiltonians import AlternativeSpinHamiltonian + +def main(): + print("Testing AlternativeSpinHamiltonian integration...") + H = AlternativeSpinHamiltonian(num_spins=3, coupling_constants=1.0) + + print("\nOne-Body Integrals:") + one_body = H.generate_one_body_integral(dense=True) + print(one_body) + + print("\nTwo-Body Integrals (Shape):") + two_body = H.generate_two_body_integral(dense=True) + print(two_body.shape) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/moha/hamiltonians.py b/moha/hamiltonians.py index fe1f320..abc9c57 100644 --- a/moha/hamiltonians.py +++ b/moha/hamiltonians.py @@ -22,7 +22,8 @@ "HamPPP", "HamHuck", "HamHub", - "HamHeisenberg" + "HamHeisenberg", + "AlternativeSpinHamiltonian" ] @@ -393,8 +394,8 @@ class HamHeisenberg(HamiltonianAPI): Models spin-1/2 particles on a lattice with the Hamiltonian:\r \r .. math::\r - \hat{H}_{XXZ} = \sum_p (\mu_p^Z - J_{pp}^{\mathrm{eq}}) S_p^Z - + \sum_{pq} J_{pq}^{\mathrm{ax}} S_p^Z S_q^Z + \hat{H}_{XXZ} = \sum_p (\mu_p^Z - J_{pp}^{\mathrm{eq}}) S_p^Z + + \sum_{pq} J_{pq}^{\mathrm{ax}} S_p^Z S_q^Z + \sum_{pq} J_{pq}^{\mathrm{eq}} (S_p^+ S_q^- + S_p^- S_q^+) \r `HamIsing` and `HamRG` are special cases of this class.\r @@ -694,3 +695,41 @@ def __init__(self, J_ax=J_ax, connectivity=connectivity ) + + +class AlternativeSpinHamiltonian(HamHeisenberg): + """ + Alternative approach to Spin Hamiltonians (Issue #179). + + Acts as an adapter to map custom spin topologies directly to the + fermion creation/annihilation operators in HamHeisenberg, avoiding + dense Kronecker products. + """ + def __init__(self, num_spins, coupling_constants, connectivity=None): + self.num_spins = int(num_spins) + + try: + J_val = float(np.array(coupling_constants)[0] if np.array(coupling_constants).size > 0 else 1.0) + except (TypeError, IndexError): + J_val = float(coupling_constants) + + if connectivity is None or len(connectivity) == 0: + self.connectivity_list = [(i, i + 1) for i in range(self.num_spins - 1)] + else: + self.connectivity_list = connectivity + + J_matrix = np.zeros((self.num_spins, self.num_spins)) + for (i, j) in self.connectivity_list: + J_matrix[i, j] = J_val + J_matrix[j, i] = J_val + + mu = np.zeros(self.num_spins) + + super().__init__( + mu=mu, + J_eq=J_matrix, + J_ax=J_matrix + ) + + + diff --git a/moha/test/test_alternative_spin.py b/moha/test/test_alternative_spin.py new file mode 100644 index 0000000..d366583 --- /dev/null +++ b/moha/test/test_alternative_spin.py @@ -0,0 +1,25 @@ +import pytest +import numpy as np +from moha.hamiltonians import AlternativeSpinHamiltonian + +def test_alternative_spin_initialization(): + """Verify that the adapter correctly maps inputs to J matrices.""" + H = AlternativeSpinHamiltonian(num_spins=3, coupling_constants=1.0) + + assert H.num_spins == 3 + assert H.J_eq.shape == (3, 3) + assert H.J_ax.shape == (3, 3) + # Check that adjacent sites are coupled + assert H.J_eq[0, 1] == 1.0 + assert H.J_eq[1, 0] == 1.0 + +def test_alternative_spin_integral_generation(): + """Verify the fermion mapping generates the correct tensor shapes.""" + H = AlternativeSpinHamiltonian(num_spins=3, coupling_constants=1.0) + + one_body = H.generate_one_body_integral(dense=True) + two_body = H.generate_two_body_integral(dense=True) + + # 3 sites means 6 spin-orbitals (3 alpha, 3 beta) + assert one_body.shape == (6, 6) + assert two_body.shape == (6, 6, 6, 6) \ No newline at end of file