-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #91 from qiboteam/refactor-ham
Refactor molecular Hamiltonian code
- Loading branch information
Showing
5 changed files
with
105 additions
and
242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1 @@ | ||
from qibochem.driver.hamiltonian import ( | ||
fermionic_hamiltonian, | ||
parse_pauli_string, | ||
qubit_hamiltonian, | ||
symbolic_hamiltonian, | ||
) | ||
from qibochem.driver.molecule import Molecule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,68 @@ | ||
""" | ||
Functions for obtaining and transforming the molecular Hamiltonian | ||
""" | ||
|
||
import openfermion | ||
from qibo import hamiltonians | ||
from qibo.symbols import X, Y, Z | ||
|
||
|
||
def fermionic_hamiltonian(oei, tei, constant): | ||
""" | ||
Build molecular Hamiltonian as an InteractionOperator using the 1-/2- electron integrals | ||
Args: | ||
oei: 1-electron integrals in the MO basis | ||
tei: 2-electron integrals in 2ndQ notation and MO basis | ||
constant: Nuclear-nuclear repulsion, and inactive Fock energy if HF embedding used | ||
Returns: | ||
Molecular Hamiltonian as an InteractionOperator | ||
""" | ||
oei_so, tei_so = openfermion.ops.representations.get_tensors_from_integrals(oei, tei) | ||
# tei_so already multiplied by 0.5, no need to include in InteractionOperator | ||
return openfermion.InteractionOperator(constant, oei_so, tei_so) | ||
|
||
|
||
def qubit_hamiltonian(fermion_hamiltonian, ferm_qubit_map): | ||
""" | ||
Converts the molecular Hamiltonian to a QubitOperator | ||
Args: | ||
fermion_hamiltonian: Molecular Hamiltonian as a InteractionOperator/FermionOperator | ||
ferm_qubit_map: Which Fermion->Qubit mapping to use | ||
Returns: | ||
qubit_operator : Molecular Hamiltonian as a QubitOperator | ||
""" | ||
# Map the fermionic molecular Hamiltonian to a QubitHamiltonian | ||
if ferm_qubit_map == "jw": | ||
q_hamiltonian = openfermion.jordan_wigner(fermion_hamiltonian) | ||
elif ferm_qubit_map == "bk": | ||
q_hamiltonian = openfermion.bravyi_kitaev(fermion_hamiltonian) | ||
else: | ||
raise KeyError("Unknown fermion->qubit mapping!") | ||
q_hamiltonian.compress() # Remove terms with v. small coefficients | ||
return q_hamiltonian | ||
|
||
|
||
def parse_pauli_string(pauli_string, coeff): | ||
""" | ||
Helper function: Converts a single Pauli string to a Qibo Symbol | ||
Args: | ||
pauli_string (tuple of tuples): Indicate what gates to apply onto which qubit | ||
e.g. ((0, 'Z'), (2, 'Z')) | ||
coeff (float): Coefficient of the Pauli string | ||
Returns: | ||
qibo.symbols.Symbol for a single Pauli string, e.g. -0.04*X0*X1*Y2*Y3 | ||
""" | ||
# Dictionary for converting | ||
xyz_to_symbol = {"X": X, "Y": Y, "Z": Z} | ||
# Check that pauli_string is non-empty | ||
if pauli_string: | ||
# pauli_string format: ((0, 'Y'), (1, 'Y'), (3, 'X')) | ||
qibo_pauli_string = 1.0 | ||
for p_letter in pauli_string: | ||
qibo_pauli_string *= xyz_to_symbol[p_letter[1]](p_letter[0]) | ||
# Include coefficient after all symbols | ||
qibo_pauli_string = coeff * qibo_pauli_string | ||
else: | ||
# Empty word, i.e. constant term in Hamiltonian | ||
qibo_pauli_string = coeff | ||
return qibo_pauli_string | ||
|
||
|
||
def symbolic_hamiltonian(q_hamiltonian): | ||
""" | ||
Converts a OpenFermion QubitOperator to a Qibo SymbolicHamiltonian | ||
Args: | ||
q_hamiltonian: QubitOperator | ||
Returns: | ||
qibo.hamiltonians.SymbolicHamiltonian | ||
""" | ||
# Sums over each individual Pauli string in the QubitOperator | ||
symbolic_ham = sum( | ||
parse_pauli_string(pauli_string, coeff) | ||
# Iterate over all operators | ||
for operator in q_hamiltonian.get_operators() | ||
# .terms gives one operator as a dictionary with one entry | ||
for pauli_string, coeff in operator.terms.items() | ||
) | ||
|
||
# Map the QubitHamiltonian to a Qibo SymbolicHamiltonian and return it | ||
return hamiltonians.SymbolicHamiltonian(symbolic_ham) | ||
""" | ||
Functions for obtaining and transforming the molecular Hamiltonian | ||
""" | ||
|
||
from functools import reduce | ||
|
||
import openfermion | ||
from qibo import symbols | ||
from qibo.hamiltonians import SymbolicHamiltonian | ||
|
||
|
||
def fermionic_hamiltonian(oei, tei, constant): | ||
""" | ||
Build molecular Hamiltonian as an InteractionOperator using the 1-/2- electron integrals | ||
Args: | ||
oei: 1-electron integrals in the MO basis | ||
tei: 2-electron integrals in 2ndQ notation and MO basis | ||
constant: Nuclear-nuclear repulsion, and inactive Fock energy if HF embedding used | ||
Returns: | ||
Molecular Hamiltonian as an InteractionOperator | ||
""" | ||
oei_so, tei_so = openfermion.ops.representations.get_tensors_from_integrals(oei, tei) | ||
# tei_so already multiplied by 0.5, no need to include in InteractionOperator | ||
return openfermion.InteractionOperator(constant, oei_so, tei_so) | ||
|
||
|
||
def qubit_hamiltonian(fermion_hamiltonian, ferm_qubit_map): | ||
""" | ||
Converts the molecular Hamiltonian to a QubitOperator | ||
Args: | ||
fermion_hamiltonian: Molecular Hamiltonian as a InteractionOperator/FermionOperator | ||
ferm_qubit_map: Which Fermion->Qubit mapping to use | ||
Returns: | ||
qubit_operator : Molecular Hamiltonian as a QubitOperator | ||
""" | ||
# Map the fermionic molecular Hamiltonian to a QubitHamiltonian | ||
if ferm_qubit_map == "jw": | ||
q_hamiltonian = openfermion.jordan_wigner(fermion_hamiltonian) | ||
elif ferm_qubit_map == "bk": | ||
q_hamiltonian = openfermion.bravyi_kitaev(fermion_hamiltonian) | ||
else: | ||
raise KeyError("Unknown fermion->qubit mapping!") | ||
q_hamiltonian.compress() # Remove terms with v. small coefficients | ||
return q_hamiltonian | ||
|
||
|
||
def qubit_to_symbolic_hamiltonian(q_hamiltonian): | ||
""" | ||
Converts a OpenFermion QubitOperator to a Qibo SymbolicHamiltonian | ||
Args: | ||
q_hamiltonian: QubitOperator | ||
Returns: | ||
qibo.hamiltonians.SymbolicHamiltonian | ||
""" | ||
symbolic_ham = sum( | ||
reduce(lambda x, y: x * y, (getattr(symbols, pauli_op)(qubit) for qubit, pauli_op in pauli_string), coeff) | ||
# Sums over each individual Pauli string in the QubitOperator | ||
for operator in q_hamiltonian.get_operators() | ||
# .terms gives one operator as a single-item dictionary, e.g. {((1: "X"), (2: "Y")): 0.33} | ||
for pauli_string, coeff in operator.terms.items() | ||
) | ||
return SymbolicHamiltonian(symbolic_ham) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.