Source code for pennylane.qchem.convert_openfermion
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# http://www.apache.org/licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""This module contains the functions for converting between OpenFermion and PennyLane objects."""fromfunctoolsimportsingledispatchfromtypingimportUnion# pylint: disable= import-outside-toplevel,no-member,unused-importimportpennylaneasqmlfrompennylaneimportnumpyasnpfrompennylane.fermi.fermionicimportFermiSentence,FermiWordfrompennylane.opsimportLinearCombination,Sumfrompennylane.qchem.convertimport_openfermion_to_pennylane,_pennylane_to_openfermiondef_import_of():"""Import openfermion."""try:# pylint: disable=import-outside-toplevel, unused-import, multiple-importsimportopenfermionexceptImportErrorasError:raiseImportError("This feature requires openfermion. ""It can be installed with: pip install openfermion.")fromErrorreturnopenfermion
[docs]deffrom_openfermion(openfermion_op,wires=None,tol=1e-16):r"""Convert OpenFermion `FermionOperator <https://quantumai.google/reference/python/openfermion/ops/FermionOperator>`__ to PennyLane :class:`~.fermi.FermiWord` or :class:`~.fermi.FermiSentence` and OpenFermion `QubitOperator <https://quantumai.google/reference/python/openfermion/ops/QubitOperator>`__ to PennyLane :class:`~.LinearCombination`. Args: openfermion_op (FermionOperator, QubitOperator): OpenFermion operator. wires (dict): Custom wire mapping used to convert the external qubit operator to a PennyLane operator. Only dictionaries with integer keys (for qubit-to-wire conversion) are accepted. If ``None``, the identity map (e.g., ``0->0, 1->1, ...``) will be used. tol (float): Tolerance for discarding negligible coefficients. Returns: Union[~.FermiWord, ~.FermiSentence, LinearCombination]: PennyLane operator. **Example** >>> import pennylane as qml >>> from openfermion import FermionOperator, QubitOperator >>> of_op = 0.5 * FermionOperator('0^ 2') + FermionOperator('0 2^') >>> pl_op = qml.from_openfermion(of_op) >>> print(pl_op) 0.5 * a⁺(0) a(2) + 1.0 * a(0) a⁺(2) >>> of_op = QubitOperator('X0', 1.2) + QubitOperator('Z1', 2.4) >>> pl_op = qml.from_openfermion(of_op) >>> print(pl_op) 1.2 * X(0) + 2.4 * Z(1) """openfermion=_import_of()ifisinstance(openfermion_op,openfermion.FermionOperator):ifwires:raiseValueError("Custom wire mapping is not supported for fermionic operators.")typemap={0:"-",1:"+"}fermi_words=[]fermi_coeffs=[]forops,valinopenfermion_op.terms.items():fw_dict={(i,op[0]):typemap[op[1]]fori,opinenumerate(ops)}fermi_words.append(FermiWord(fw_dict))fermi_coeffs.append(val)iflen(fermi_words)==1andfermi_coeffs[0]==1.0:returnfermi_words[0]pl_op=FermiSentence(dict(zip(fermi_words,fermi_coeffs)))pl_op.simplify(tol=tol)returnpl_opcoeffs,pl_ops=_openfermion_to_pennylane(openfermion_op,wires=wires,tol=tol)pennylane_op=qml.ops.LinearCombination(coeffs,pl_ops)returnpennylane_op
[docs]defto_openfermion(pennylane_op:Union[Sum,LinearCombination,FermiWord,FermiSentence],wires=None,tol=1.0e-16):r"""Convert a PennyLane operator to OpenFermion `QubitOperator <https://quantumai.google/reference/python/openfermion/ops/QubitOperator>`__ or `FermionOperator <https://quantumai.google/reference/python/openfermion/ops/FermionOperator>`__. Args: pennylane_op (~ops.op_math.Sum, ~ops.op_math.LinearCombination, ~.FermiWord, ~.FermiSentence): PennyLane operator wires (dict): Custom wire mapping used to convert a PennyLane qubit operator to the external operator. Only dictionaries with integer keys (for qubit-to-wire conversion) are accepted. If ``None``, the identity map (e.g., ``0->0, 1->1, ...``) will be used. Returns: (QubitOperator, FermionOperator): OpenFermion operator **Example** >>> import pennylane as qml >>> w1 = qml.FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> w2 = qml.FermiWord({(0, 1) : '+', (1, 2) : '-'}) >>> fermi_s = qml.FermiSentence({w1 : 1.2, w2: 3.1}) >>> of_fermi_op = qml.to_openfermion(fermi_s) >>> of_fermi_op 1.2 [0^ 1] + 3.1 [1^ 2] >>> sum_op = 1.2 * qml.X(0) + 2.4 * qml.Z(1) >>> of_qubit_op = qml.to_openfermion(sum_op) >>> of_qubit_op (1.2+0j) [X0] + (2.4+0j) [Z1] """return_to_openfermion_dispatch(pennylane_op,wires=wires,tol=tol)
@singledispatchdef_to_openfermion_dispatch(pl_op,wires=None,tol=1.0e-16):"""Dispatches to appropriate function if pl_op is a ``Sum``, ``LinearCombination, ``FermiWord`` or ``FermiSentence``."""raiseValueError(f"pl_op must be a Sum, LinearCombination, FermiWord or FermiSentence, got: {type(pl_op)}.")@_to_openfermion_dispatch.registerdef_(pl_op:Sum,wires=None,tol=1.0e-16):coeffs,ops=pl_op.terms()return_pennylane_to_openfermion(np.array(coeffs),ops,wires=wires,tol=tol)# pylint: disable=unused-argument, protected-access@_to_openfermion_dispatch.registerdef_(ops:FermiWord,wires=None,tol=1.0e-16):openfermion=_import_of()ifwires:raiseValueError("Custom wire mapping is not supported for fermionic operators.")returnopenfermion.ops.FermionOperator(qml.fermi.fermionic._to_string(ops,of=True))@_to_openfermion_dispatch.registerdef_(pl_op:FermiSentence,wires=None,tol=1.0e-16):openfermion=_import_of()ifwires:raiseValueError("Custom wire mapping is not supported for fermionic operators.")fermion_op=openfermion.ops.FermionOperator()forfermi_wordinpl_op:ifnp.abs(pl_op[fermi_word].imag)<tol:fermion_op+=pl_op[fermi_word].real*to_openfermion(fermi_word)else:fermion_op+=pl_op[fermi_word]*to_openfermion(fermi_word)returnfermion_op