Source code for qiskit_nature.second_q.hamiltonians.heisenberg_model

# This code is part of a Qiskit project.
# (C) Copyright IBM 2022, 2023.
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""The Heisenberg model."""

from __future__ import annotations
from fractions import Fraction
import numpy as np
from qiskit_nature.second_q.operators import SpinOp

from .lattice_model import LatticeModel
from .lattices import Lattice

[docs]class HeisenbergModel(LatticeModel): r"""The Heisenberg model. This class implements the following Hamiltonian: .. math:: H = - \vec{J} \sum_{\langle i, j \rangle} \vec{\sigma}_{i} \otimes \vec{\sigma}_{j} - \vec{h} \sum_{i} \vec{\sigma}_{i} where :math:`i,j` refer to lattice nodes. The :math:`\sum_{\langle i, j \rangle}` is performed over adjacent lattice nodes. This model assumes spin-:math:`\frac{1}{2}` particles. Thus, :math:`\vec{\sigma}_{i} = (X_i, Y_i, Z_i)` is a vector containing the Pauli matrices. :math:`\vec{J}` is the coupling constant and :math:`\vec{h}` is the external magnetic field, both with dimensions of energy. This model is instantiated using a :class:`~qiskit_nature.second_q.hamiltonians.lattices.Lattice`. For example, using a :class:`~qiskit_nature.second_q.hamiltonians.lattices.LineLattice`: .. code-block:: python line_lattice = LineLattice(num_nodes=10, boundary_condition=BoundaryCondition.OPEN) heisenberg_model = HeisenbergModel(line_lattice, (1.0, 1.0, 1.0), (0.0, 0.0, 1.0)) The transverse-field Ising model can be recovered as a special case of the Heisenberg model by limiting the model to spins that are parallel/antiparallel with respect to a transverse magnetic field: .. code-block:: python heisenberg_model = HeisenbergModel(line_lattice, (0.0, 0.0, 1.0), (1.0, 0.0, 0.0)) """ def __init__( self, lattice: Lattice, coupling_constants: tuple = (1.0, 1.0, 1.0), ext_magnetic_field: tuple = (0.0, 0.0, 0.0), ) -> None: """ Args: lattice: Lattice on which the model is defined. coupling_constants: The coupling constants in each Cartesian axis. Defaults to ``(1.0, 1.0, 1.0)``. ext_magnetic_field: Represents a magnetic field in Cartesian coordinates. Defaults to ``(0.0, 0.0, 0.0)``. """ super().__init__(lattice) self.coupling_constants = coupling_constants self.ext_magnetic_field = ext_magnetic_field @property def register_length(self) -> int: return self._lattice.num_nodes
[docs] def second_q_op(self) -> SpinOp: """Return the Hamiltonian of the Heisenberg model in terms of ``SpinOp``. Returns: SpinOp: The Hamiltonian of the Heisenberg model. """ hamiltonian = {} weighted_edge_list = self.lattice.weighted_edge_list for node_a, node_b, _ in weighted_edge_list: if node_a == node_b: index = node_a for axis, coeff in zip("XYZ", self.ext_magnetic_field): if not np.isclose(coeff, 0.0): hamiltonian[f"{axis}_{index}"] = coeff else: index_left = node_a index_right = node_b for axis, coeff in zip("XYZ", self.coupling_constants): if not np.isclose(coeff, 0.0): hamiltonian[f"{axis}_{index_left} {axis}_{index_right}"] = coeff return SpinOp(hamiltonian, spin=Fraction(1, 2), num_spins=self.lattice.num_nodes)