Source code for qarp.operators.compat

"""openfermion interop: converters between the qarpx operator classes and
openfermion's, and openfermion's MSB matrix layout.

openfermion is NOT a runtime dependency of qarp — the converters are for
research code and notebooks that still exchange operators with openfermion
(install it via the ``openqarp[openfermion]`` extra); :func:`get_sparse_operator`
needs no openfermion at all, only its bit order.
"""

import scipy.sparse

import qarpx as _qx


def _openfermion():
    try:
        import openfermion
    except ImportError as exc:  # pragma: no cover - error path
        raise ImportError(
            "openfermion is required for qarp.operators.compat converters; "
            "install it with `pip install openqarp[openfermion]`."
        ) from exc
    return openfermion


[docs] def to_openfermion(operator): """Convert a qarpx FermionOperator/QubitOperator to its openfermion equivalent (exact term dict copy).""" openfermion = _openfermion() if isinstance(operator, _qx.FermionOperator): out = openfermion.FermionOperator() elif isinstance(operator, _qx.QubitOperator): out = openfermion.QubitOperator() else: raise TypeError(f"Cannot convert {type(operator).__name__} to openfermion.") out.terms = dict(operator.terms) return out
[docs] def from_openfermion(operator): """Convert an openfermion FermionOperator/QubitOperator to the qarpx equivalent (exact term dict copy).""" openfermion = _openfermion() if isinstance(operator, openfermion.FermionOperator): out = _qx.FermionOperator() elif isinstance(operator, openfermion.QubitOperator): out = _qx.QubitOperator() else: raise TypeError(f"Cannot convert {type(operator).__name__} from openfermion.") out.terms = dict(operator.terms) return out
[docs] def get_sparse_operator(operator, n_qubits=None): """The matrix ``openfermion.get_sparse_operator`` would return. ``scipy.sparse.csc_matrix`` with **qubit 0 as the most-significant bit** (openfermion / cirq / pennylane layout). Interop only — qarp code uses ``operator.sparse_matrix()`` (LSB, conventions §1); the two differ by :func:`qarp.endianness.msb_to_lsb_matrix`. FermionOperators go through Jordan-Wigner, matching openfermion's ``jordan_wigner_sparse`` up to float rounding. """ if isinstance(operator, _qx.FermionOperator): data, rows, cols, dim = _qx.fermion_operator_coo(operator, n_qubits, msb=True) elif isinstance(operator, _qx.QubitOperator): data, rows, cols, dim = _qx.qubit_operator_coo(operator, n_qubits, msb=True) else: raise TypeError(f"Failed to convert {type(operator).__name__} to a sparse operator.") return scipy.sparse.csc_matrix((data, (rows, cols)), shape=(dim, dim))
__all__ = ["to_openfermion", "from_openfermion", "get_sparse_operator"]