Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QubitOperator import from Tangelo, for better encapsulation #299

Merged
merged 27 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
23104ce
Integrate bug fix into main before release (#278) (#279)
ValentinS4t1qbit Feb 17, 2023
cf6f723
Depth function dramatically accelerated through breakthrough lookup d…
Feb 25, 2023
d77988d
Clean up
Feb 27, 2023
808e361
Merge branch 'goodchemistryco:develop' into develop
ValentinS4t1qbit Mar 8, 2023
940ed65
Merge branch 'goodchemistryco:develop' into develop
ValentinS4t1qbit Mar 17, 2023
e364a4d
Merge branch 'goodchemistryco:develop' into develop
ValentinS4t1qbit Apr 7, 2023
3729e94
Small fixes & exposing NoiseModel to a higher level
May 4, 2023
30c0707
QubitOperator imports focused on Tangelo, wip
May 4, 2023
fd080b4
Encapsulated get_sparse_op for both Fermion and QubitOperator. Small …
May 4, 2023
d8dcae0
Less ambiguous convertion to Openfermion, more homogeneous
May 4, 2023
c4d0a2a
Trim trivial qubits from circuit and Hamiltonian (#296)
elloyd-1qbit May 16, 2023
a503c39
Revert "Trim trivial qubits from circuit and Hamiltonian (#296)" (#301)
ValentinS4t1qbit May 17, 2023
6940f3b
Get_sparse_operator called externally by openfermion, after conversio…
May 23, 2023
be8d413
Get_sparse_operator called externally by openfermion, after conversio…
May 23, 2023
7332922
Get_sparse_operator called externally by openfermion, after conversio…
May 24, 2023
b5b0c41
Get_sparse_operator called externally by openfermion, after conversio…
May 24, 2023
c203131
boop.
Jun 6, 2023
c779327
Merge branch 'goodchemistryco:main' into small_stuff
ValentinS4t1qbit Jun 15, 2023
44dbc12
Merge branch 'small_stuff' of https://github.com/ValentinS4t1qbit/Tan…
Jun 15, 2023
4bd49ff
revert change
Jun 15, 2023
aab704f
revert change
Jun 15, 2023
b237bc5
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 15, 2023
c93d990
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 15, 2023
db46786
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 15, 2023
ec7b7fd
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 15, 2023
49038ee
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 16, 2023
23145ac
openfermion qubitops can now be loaded into Tangelo ops directly
Jun 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions tangelo/algorithms/variational/vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@

from enum import Enum
import numpy as np
from openfermion.ops.operators.qubit_operator import QubitOperator

from tangelo.helpers.utils import HiddenPrints
from tangelo.linq import get_backend, Circuit
from tangelo.linq.helpers.circuits.measurement_basis import measurement_basis_gates
from tangelo.toolboxes.operators import count_qubits, FermionOperator
from tangelo.toolboxes.operators import count_qubits, FermionOperator, QubitOperator
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping
from tangelo.toolboxes.qubit_mappings.statevector_mapping import get_mapped_vector, vector_to_circuit
from tangelo.toolboxes.post_processing.bootstrapping import get_resampled_frequencies
Expand Down
1 change: 1 addition & 0 deletions tangelo/linq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
from .simulator import get_backend
from .target.backend import get_expectation_value_from_frequencies_oneterm
from .target import backend_info, Backend
from .noisy_simulation import NoiseModel
29 changes: 11 additions & 18 deletions tangelo/linq/target/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,18 @@
import numpy as np
from scipy import stats
from bitarray import bitarray
from openfermion.ops import QubitOperator

from tangelo.linq import Gate, Circuit
from tangelo.linq.helpers.circuits.measurement_basis import measurement_basis_gates
from tangelo.toolboxes.operators import QubitOperator


def get_expectation_value_from_frequencies_oneterm(term, frequencies):
"""Return the expectation value of a single-term qubit-operator, given
the result of a state-preparation.

Args:
term (openfermion-style QubitOperator object): a qubit operator, with
only a single term.
term (QubitOperator): a single-term qubit operator.
frequencies (dict): histogram of frequencies of measurements (assumed
to be in lsq-first format).

Expand Down Expand Up @@ -82,8 +81,7 @@ def get_variance_from_frequencies_oneterm(term, frequencies):
"""Return the variance of the expectation value of a single-term qubit-operator, given
the result of a state-preparation.
Args:
term (openfermion-style QubitOperator object): a qubit operator, with
only a single term.
term (QubitOperator): a single-term qubit operator.
frequencies (dict): histogram of frequencies of measurements (assumed
to be in lsq-first format).
Returns:
Expand Down Expand Up @@ -315,8 +313,7 @@ def get_expectation_value(self, qubit_operator, state_prep_circuit, initial_stat
actual QPU.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubit
operator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation.
initial_statevector (array): The initial statevector for the simulation
desired_meas_result (str): The mid-circuit measurement results to select for.
Expand Down Expand Up @@ -376,8 +373,7 @@ def get_variance(self, qubit_operator, state_prep_circuit, initial_statevector=N
actual QPU.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubit
operator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation.
initial_statevector (list/array) : A valid statevector in the format
supported by the target backend.
Expand Down Expand Up @@ -431,8 +427,7 @@ def get_standard_error(self, qubit_operator, state_prep_circuit, initial_stateve
actual QPU.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubit
operator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation.
initial_statevector (list/array): A valid statevector in the format
supported by the target backend.
Expand All @@ -452,7 +447,7 @@ def _get_expectation_value_from_statevector(self, qubit_operator, state_prep_cir
this function directly, please call "get_expectation_value" instead.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubit operator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation (only pure states).
initial_statevector (array): The initial state of the system

Expand Down Expand Up @@ -503,7 +498,7 @@ def _get_expectation_value_from_frequencies(self, qubit_operator, state_prep_cir
using the frequencies of observable states.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubitoperator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation.
initial_statevector (array): The initial state of the system
desired_meas_result (str): The mid-circuit measurement results to select for.
Expand Down Expand Up @@ -551,7 +546,7 @@ def _get_variance_from_frequencies(self, qubit_operator, state_prep_circuit, ini
using the frequencies of observable states.

Args:
qubit_operator (openfermion-style QubitOperator class): a qubit operator.
qubit_operator (QubitOperator): the qubit operator.
state_prep_circuit (Circuit): an abstract circuit used for state preparation.
initial_statevector (list/array) : A valid statevector in the format
supported by the target backend.
Expand Down Expand Up @@ -599,8 +594,7 @@ def get_expectation_value_from_frequencies_oneterm(term, frequencies):
the result of a state-preparation.

Args:
term (openfermion-style QubitOperator object): a qubit operator, with
only a single term.
term (QubitOperator): a single-term qubit operator
frequencies (dict): histogram of frequencies of measurements (assumed
to be in lsq-first format).

Expand All @@ -617,8 +611,7 @@ def get_variance_from_frequencies_oneterm(term, frequencies):
the result of a state-preparation.

Args:
term (openfermion-style QubitOperator object): a qubit operator, with
only a single term.
term (QubitOperator): a single-term qubit operator.
frequencies (dict): histogram of frequencies of measurements (assumed
to be in lsq-first format).

Expand Down
7 changes: 3 additions & 4 deletions tangelo/linq/tests/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@
import time

import numpy as np
from openfermion.ops import QubitOperator
from openfermion import load_operator, get_sparse_operator

from tangelo.toolboxes.operators import QubitOperator
from tangelo.linq import Gate, Circuit, get_backend
from tangelo.linq.translator import translate_circuit as translate_c
from tangelo.linq.gate import PARAMETERIZED_GATES
from tangelo.helpers.utils import installed_simulator, installed_sv_simulator, installed_backends
from tangelo.linq.target.backend import Backend, get_expectation_value_from_frequencies_oneterm
from tangelo.helpers.utils import assert_freq_dict_almost_equal
from tangelo.helpers.utils import installed_simulator, installed_sv_simulator, installed_backends, assert_freq_dict_almost_equal

path_data = os.path.dirname(os.path.abspath(__file__)) + '/data'

Expand Down Expand Up @@ -425,7 +424,7 @@ def test_get_exp_value_mixed_state_desired_measurement_with_shots(self):
""" Get expectation value of mixed state by post-selecting on desired measurement."""
qubit_operator = QubitOperator("X0 X1") + QubitOperator("Y0 Y1") + QubitOperator("Z0 Z1") + QubitOperator("X0 Y1", 1j)

ham = get_sparse_operator(qubit_operator).toarray()
ham = get_sparse_operator(qubit_operator.to_openfermion()).toarray()
exact_sv = np.array([0.+0.j, 0.+0.j, 0.87758256+0.j, -0.47942554+0.j])
exact_exp = np.vdot(exact_sv, ham @ exact_sv)

Expand Down
2 changes: 1 addition & 1 deletion tangelo/linq/tests/test_simulator_noisy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
import unittest

import numpy as np
from openfermion.ops import QubitOperator

from tangelo.linq import Gate, Circuit, get_backend, backend_info
from tangelo.linq.noisy_simulation import NoiseModel, get_qiskit_noise_dict
from tangelo.helpers.utils import default_simulator, installed_backends, assert_freq_dict_almost_equal
from tangelo.toolboxes.operators import QubitOperator

# Noisy simulation: circuits, noise models, references
cn1 = Circuit([Gate('X', target=0)])
Expand Down
3 changes: 1 addition & 2 deletions tangelo/toolboxes/ansatz_generator/ansatz_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@

import numpy as np
from openfermion.ops import FermionOperator as ofFermionOperator
from openfermion.ops import InteractionOperator as ofInteractionOperator
from openfermion.ops import QubitOperator as ofQubitOperator

from tangelo.linq import Circuit, Gate
from tangelo.toolboxes.operators import FermionOperator, QubitOperator
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping, get_fermion_operator
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping


def pauli_op_to_gate(index, op, inverse=False):
Expand Down
16 changes: 8 additions & 8 deletions tangelo/toolboxes/ansatz_generator/tests/test_ansatz_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_trotterize_fermion_input(self):
n_electrons=mol_H4_sto3g.n_active_electrons,
up_then_down=True)

ham_mat = get_sparse_operator(qubit_hamiltonian).toarray()
ham_mat = get_sparse_operator(qubit_hamiltonian.to_openfermion()).toarray()
evolve_exact = expm(-1j * time * ham_mat) @ refwave

options = {"up_then_down": True,
Expand Down Expand Up @@ -75,7 +75,7 @@ def test_trotterize_qubit_input(self):
n_electrons=mol_H4_sto3g.n_active_electrons,
up_then_down=True)

ham_mat = get_sparse_operator(qubit_hamiltonian).toarray()
ham_mat = get_sparse_operator(qubit_hamiltonian.to_openfermion()).toarray()
evolve_exact = expm(-1j * time * ham_mat) @ refwave

tcircuit, phase = trotterize(qubit_hamiltonian, trotter_order=1, n_trotter_steps=1, time=time,
Expand Down Expand Up @@ -103,7 +103,7 @@ def test_trotterize_different_order_and_steps(self):
n_electrons=mol_H4_sto3g.n_active_electrons,
up_then_down=True)

ham_mat = get_sparse_operator(qubit_hamiltonian).toarray()
ham_mat = get_sparse_operator(qubit_hamiltonian.to_openfermion()).toarray()
evolve_exact = expm(-1j * time * ham_mat) @ refwave

for trotter_order, n_trotter_steps in [(1, 1), (2, 1), (1, 2), (4, 1), (6, 1)]:
Expand Down Expand Up @@ -144,7 +144,7 @@ def test_trotterize_fermionic_input_different_times(self):
total_fermion_operator += fermion_operators[i]
qubit_hamiltonian = fermion_to_qubit_mapping(fermion_operator=fermion_operators[i],
mapping=mapping)
ham_mat = get_sparse_operator(qubit_hamiltonian, n_qubits=4).toarray()
ham_mat = get_sparse_operator(qubit_hamiltonian.to_openfermion(), n_qubits=4).toarray()
evolve_exact = expm(-1j * time[next(iter(fermion_operators[i].terms))] * ham_mat) @ evolve_exact

# Apply trotter-suzuki steps using different times for each term
Expand All @@ -171,7 +171,7 @@ def test_trotterize_qubit_input_different_times(self):
# Exactly evolve for each time step
evolve_exact = refwave
for i in range(3):
ham_mat = get_sparse_operator(qubit_operator_list[i], n_qubits=4).toarray()
ham_mat = get_sparse_operator(qubit_operator_list[i].to_openfermion(), n_qubits=4).toarray()
evolve_exact = expm(-1j * time[next(iter(qubit_operator_list[i].terms))] * ham_mat) @ evolve_exact

# Apply trotter-suzuki with different times for each qubit operator term
Expand Down Expand Up @@ -219,7 +219,7 @@ def test_controlled_time_evolution_by_phase_estimation(self):
qu_op = (QubitOperator("X0 X1", 0.125) + QubitOperator("Y1 Y2", 0.125) + QubitOperator("Z2 Z3", 0.125)
+ QubitOperator("", 0.125))

ham_mat = get_sparse_operator(qu_op).toarray()
ham_mat = get_sparse_operator(qu_op.to_openfermion()).toarray()
_, wavefunction = eigh(ham_mat)

# Append four qubits in the zero state to eigenvector 9
Expand Down Expand Up @@ -275,9 +275,9 @@ def test_derangement_circuit_by_estimating_pauli_string(self):
qu_op = QubitOperator("X0 Y1", 0.125) + QubitOperator("Y1 Y2", 0.125) + QubitOperator("Z2 Z3", 0.125)
pa = QubitOperator("X0 X1 X2 X3", 1)

ham_mat = get_sparse_operator(qu_op).toarray()
ham_mat = get_sparse_operator(qu_op.to_openfermion()).toarray()
_, wavefunction = eigh(ham_mat)
pamat = get_sparse_operator(pa).toarray()
pamat = get_sparse_operator(pa.to_openfermion()).toarray()

mixed_wave = np.sqrt(3)/2*wavefunction[:, -1] + 1/2*wavefunction[:, 0]
mixed_wave_3 = np.kron(np.kron(mixed_wave, mixed_wave), mixed_wave)
Expand Down
16 changes: 10 additions & 6 deletions tangelo/toolboxes/ansatz_generator/tests/test_vsqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
import numpy as np
from openfermion import load_operator

from tangelo.linq import get_backend
from tangelo.molecule_library import mol_H2_sto3g
from tangelo.toolboxes.operators import QubitOperator
from tangelo.toolboxes.qubit_mappings import jordan_wigner, symmetry_conserving_bravyi_kitaev
from tangelo.toolboxes.ansatz_generator import VSQS
from tangelo.linq import get_backend
from tangelo.toolboxes.qubit_mappings.statevector_mapping import get_reference_circuit

# For openfermion.load_operator function.
Expand Down Expand Up @@ -71,17 +71,21 @@ def test_vsqs_H2(self):
self.assertAlmostEqual(energy, -1.1372701255155757, delta=1e-6)

def test_vsqs_H4_doublecation(self):
"""Verify closed-shell VSQS functionalities for H4 2+ by using saved qubit hamiltonian and initial hamiltonian"""
""" Verify closed-shell VSQS functionalities for H4 2+ by using saved qubit and initial hamiltonians """

var_params = [-2.53957674, 0.72683888, 1.08799500, 0.49836183,
-0.23020698, 0.93278630, 0.50591026, 0.50486903]

# Build qubit hamiltonian for energy evaluation
qubit_hamiltonian = load_operator("mol_H4_doublecation_minao_qubitham_jw_b.data", data_directory=pwd_this_test+"/data", plain_text=True)
initial_hamiltonian = load_operator("mol_H4_doublecation_minao_init_qubitham_jw_b.data", data_directory=pwd_this_test+"/data", plain_text=True)
reference_state = get_reference_circuit(8, 2, "jw", up_then_down=True, spin=0)
# Build qubit hamiltonian for energy evaluation, loading them with Openfermion.
qubit_ofhamiltonian = load_operator("mol_H4_doublecation_minao_qubitham_jw_b.data", data_directory=pwd_this_test+"/data", plain_text=True)
initial_ofhamiltonian = load_operator("mol_H4_doublecation_minao_init_qubitham_jw_b.data", data_directory=pwd_this_test+"/data", plain_text=True)

# Load into Tangelo operators
qubit_hamiltonian = QubitOperator.from_openfermion(qubit_ofhamiltonian)
initial_hamiltonian = QubitOperator.from_openfermion(initial_ofhamiltonian)

# Build circuit
reference_state = get_reference_circuit(8, 2, "jw", up_then_down=True, spin=0)
vsqs_ansatz = VSQS(qubit_hamiltonian=qubit_hamiltonian, h_init=initial_hamiltonian, reference_state=reference_state,
intervals=5, time=5, trotter_order=2)
vsqs_ansatz.build_circuit()
Expand Down
11 changes: 7 additions & 4 deletions tangelo/toolboxes/ansatz_generator/uccgd.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@

import numpy as np
from openfermion import hermitian_conjugated
from openfermion import FermionOperator as ofFermionOperator
from itertools import combinations_with_replacement, product

from tangelo.linq import Circuit
from tangelo.toolboxes.operators import FermionOperator
from tangelo.toolboxes.ansatz_generator.ansatz import Ansatz
from tangelo.toolboxes.ansatz_generator.ansatz_utils import get_exponentiated_qubit_operator_circuit
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping
Expand Down Expand Up @@ -180,16 +180,16 @@ def _get_qubit_operator(self):
Returns:
QubitOperator: qubit-encoded elements of the UCCGD
"""
fermion_op = ofFermionOperator()
fermion_op = FermionOperator()
n_mos = self.n_spinorbitals // 2
p = -1
for indices in combinations_with_replacement(range(n_mos), 4):
if len(set(indices)) >= 2: # are they not all equal
u, w, v, t = indices
p = p + 1
for sig, tau in product(range(2), repeat=2):
c_op = ofFermionOperator(((2*t+sig, 1), (2*v+tau, 1), (2*w+tau, 0), (2*u+sig, 0)), self.var_params[p])
c_op += ofFermionOperator(((2*v+sig, 1), (2*t+tau, 1), (2*u+tau, 0), (2*w+sig, 0)), self.var_params[p])
c_op = FermionOperator(((2*t+sig, 1), (2*v+tau, 1), (2*w+tau, 0), (2*u+sig, 0)), self.var_params[p])
c_op += FermionOperator(((2*v+sig, 1), (2*t+tau, 1), (2*u+tau, 0), (2*w+sig, 0)), self.var_params[p])
fermion_op += c_op - hermitian_conjugated(c_op)

qubit_op = fermion_to_qubit_mapping(fermion_operator=fermion_op,
Expand All @@ -198,6 +198,9 @@ def _get_qubit_operator(self):
n_electrons=self.n_electrons,
up_then_down=self.up_then_down)

print(type(fermion_op))
print(type(qubit_op))

# Cast all coefs to floats (rotations angles are real)
for key in qubit_op.terms:
qubit_op.terms[key] = float(qubit_op.terms[key].imag)
Expand Down
7 changes: 3 additions & 4 deletions tangelo/toolboxes/ansatz_generator/vsqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
Adiabatic State Preparation (ASP) inspired ansatz as described in https://arxiv.org/abs/2003.09913."""

import numpy as np
from openfermion import QubitOperator as ofQubitOperator

from .ansatz import Ansatz
from .ansatz_utils import get_exponentiated_qubit_operator_circuit
from tangelo.toolboxes.operators import FermionOperator
from tangelo.linq import Circuit
from tangelo.toolboxes.operators import FermionOperator, QubitOperator
from tangelo.toolboxes.qubit_mappings.mapping_transform import get_qubit_number, fermion_to_qubit_mapping
from tangelo.toolboxes.qubit_mappings.statevector_mapping import get_reference_circuit

Expand Down Expand Up @@ -68,7 +67,7 @@ def __init__(self, molecule=None, mapping="jw", up_then_down=False, intervals=2,

if molecule is None:
self.qubit_hamiltonian = qubit_hamiltonian
if not isinstance(h_init, ofQubitOperator):
if not isinstance(h_init, QubitOperator):
raise ValueError("When providing a qubit hamiltonian, an initial qubit Hamiltonian must also be provided")
self.h_init = h_init
if not isinstance(reference_state, Circuit):
Expand Down Expand Up @@ -102,7 +101,7 @@ def qu_op_to_list(qu_op):
self.stride = 2
self.n_h_nav = 0
else:
if isinstance(self.h_nav, ofQubitOperator):
if isinstance(self.h_nav, QubitOperator):
self.stride = 3
self.h_nav_list = qu_op_to_list(self.h_nav)
self.n_h_nav = len(self.h_nav_list)
Expand Down
4 changes: 2 additions & 2 deletions tangelo/toolboxes/circuits/tests/test_diagonal_coulomb.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import unittest

from openfermion import get_sparse_operator, linalg
from openfermion import linalg, get_sparse_operator

from tangelo.linq import get_backend, Circuit
from tangelo.molecule_library import mol_H4_sto3g
Expand All @@ -24,7 +24,7 @@
sim = get_backend(target="cirq")


class diagonal_coulomb_Test(unittest.TestCase):
class DiagonalCoulombTest(unittest.TestCase):

def test_orbital_rotations(self):
"""Test calculating energy expectation value of H4 hamiltonian by decomposing into diagional terms"""
Expand Down
Loading