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

Ilc ansatz #132

Merged
merged 37 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4c548a1
Add ILC ansatz class
MPCoons Feb 16, 2022
a2e122e
updates to qmf, qcc, and ilc ansatz classes
MPCoons Feb 16, 2022
3ea245c
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Feb 16, 2022
808e0f9
enable QMF and ILC classes to read-in and process data from OpenFermi…
MPCoons Feb 17, 2022
344bbb4
fixes to ILC ansatz; tests for selected FNO and MI-FNO Hamiltonians f…
MPCoons Feb 17, 2022
43a9e54
cleaning up ILC ansatz files; updated tests for Be system: tests for …
MPCoons Feb 22, 2022
896fc30
small changes to ilc.py
MPCoons Feb 24, 2022
0c147a9
improvements to qmf, qcc, ilc, and tests
MPCoons Mar 2, 2022
35bb175
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Mar 2, 2022
eac23ca
improvements to qmf, qcc, and ilc ansatze
MPCoons Mar 7, 2022
5e23f3c
improvements to qmf, qcc, and ilc ansatze
MPCoons Mar 7, 2022
dbb1452
added ILC ansatz to vqesolver and test_vqe_solver
MPCoons Mar 9, 2022
9820d4b
added ILC ansatz to vqesolver and test_vqe_solver
MPCoons Mar 9, 2022
50c66c0
last set of revisions to prepare the ilc_ansatz branch for PR
MPCoons Mar 10, 2022
88f33c3
last set of revisions to prepare the ilc_ansatz branch for PR
MPCoons Mar 10, 2022
5b9d913
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Mar 15, 2022
9c8a9c7
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Mar 16, 2022
0676b93
first round of revisions of the PR
MPCoons Mar 22, 2022
70a109f
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Mar 22, 2022
18d7a97
fix to gauss_elim_over_gf2
MPCoons Mar 22, 2022
81d10a2
second batch of PR revisions
MPCoons Mar 22, 2022
f1f4e7e
improvements to qcc and ilc; added a test for gaussian elim over GF(2)
MPCoons Mar 23, 2022
df8eee5
minor change to a file to prompt check
MPCoons Mar 23, 2022
5280740
minor change to a file to prompt check
MPCoons Mar 23, 2022
2f18cd9
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons Apr 4, 2022
25d83ab
added comments to Gaussian elimination function; added a warning when…
MPCoons Apr 19, 2022
34d3ea1
fixed issues prevented merge of test_vqe_solver.py
MPCoons Apr 19, 2022
7110b94
fixed indentation error; added initial_var_params for qmf, qcc, and i…
MPCoons Apr 19, 2022
592e06e
addressed errors with test_vqe_solver
MPCoons Apr 19, 2022
851b676
cleaned up construct_acs function and tests related to Gaussian elimi…
MPCoons Apr 22, 2022
89f08ca
updating ilc_ansatz branch with main
MPCoons May 3, 2022
fab6729
last round of revisions to ilc_ansatz branch before merge
MPCoons May 5, 2022
a6f2803
Merge branch 'develop' of https://github.com/goodchemistryco/Tangelo …
MPCoons May 5, 2022
a7a4e9b
last round of revisions to ilc_ansatz branch before merge
MPCoons May 5, 2022
ac6e6e3
fixed merge issues due to conflicts in vqe_solver.py
MPCoons May 9, 2022
cc004ff
Update vqe_solver.py
ValentinS4t1qbit May 10, 2022
6dfd719
Update vqe_solver.py
ValentinS4t1qbit May 10, 2022
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
54 changes: 46 additions & 8 deletions tangelo/algorithms/variational/tests/test_vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
from tangelo.algorithms import BuiltInAnsatze, VQESolver
from tangelo.molecule_library import mol_H2_sto3g, mol_H4_sto3g, mol_H4_cation_sto3g, mol_NaH_sto3g, mol_H4_sto3g_symm
from tangelo.toolboxes.ansatz_generator.uccsd import UCCSD
from tangelo.toolboxes.ansatz_generator.qmf import QMF
from tangelo.toolboxes.ansatz_generator.qcc import QCC
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping
from tangelo.toolboxes.molecular_computation.rdms import matricize_2rdm
from tangelo.toolboxes.optimizers.rotosolve import rotosolve
Expand Down Expand Up @@ -119,7 +117,7 @@ def test_simulate_qmf_h2(self):
"""

vqe_options = {"molecule": mol_H2_sto3g, "ansatz": BuiltInAnsatze.QMF, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

Expand All @@ -131,7 +129,20 @@ def test_simulate_qcc_h2(self):
parameters, exact simulator.
"""
vqe_options = {"molecule": mol_H2_sto3g, "ansatz": BuiltInAnsatze.QCC, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

energy = vqe_solver.simulate()
self.assertAlmostEqual(energy, -1.137270, delta=1e-4)

def test_simulate_ilc_h2(self):
"""Run VQE on H2 molecule, with ILC ansatz, JW qubit mapping, initial
parameters, exact simulator.
"""

vqe_options = {"molecule": mol_H2_sto3g, "ansatz": BuiltInAnsatze.ILC, "qubit_mapping": "jw",
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

Expand Down Expand Up @@ -209,7 +220,7 @@ def test_simulate_qmf_h4(self):
"""

vqe_options = {"molecule": mol_H4_sto3g, "ansatz": BuiltInAnsatze.QMF, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

Expand All @@ -220,14 +231,28 @@ def test_simulate_qcc_h4(self):
"""Run VQE on H4 molecule, with QCC ansatz, JW qubit mapping, initial
parameters, exact simulator.
"""

vqe_options = {"molecule": mol_H4_sto3g, "ansatz": BuiltInAnsatze.QCC, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

energy = vqe_solver.simulate()
self.assertAlmostEqual(energy, -1.963270, delta=1e-4)

def test_simulate_ilc_h4(self):
"""Run VQE on H4 molecule, with ILC ansatz, JW qubit mapping, initial
parameters, exact simulator.
"""

vqe_options = {"molecule": mol_H4_sto3g, "ansatz": BuiltInAnsatze.ILC, "qubit_mapping": "jw",
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

energy = vqe_solver.simulate()
self.assertAlmostEqual(energy, -1.960877, delta=1e-4)

def test_simulate_h4_open(self):
"""Run VQE on H4 molecule, with UCCSD ansatz, JW qubit mapping, initial parameters, exact simulator """
vqe_options = {"molecule": mol_H4_cation_sto3g, "ansatz": BuiltInAnsatze.UCCSD, "qubit_mapping": "jw",
Expand All @@ -244,7 +269,7 @@ def test_simulate_qmf_h4_open(self):
"""

vqe_options = {"molecule": mol_H4_cation_sto3g, "ansatz": BuiltInAnsatze.QMF, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

Expand All @@ -257,7 +282,20 @@ def test_simulate_qcc_h4_open(self):
"""

vqe_options = {"molecule": mol_H4_cation_sto3g, "ansatz": BuiltInAnsatze.QCC, "qubit_mapping": "jw",
"verbose": True}
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

energy = vqe_solver.simulate()
self.assertAlmostEqual(energy, -1.638020, delta=1e-4)

def test_simulate_ilc_h4_open(self):
"""Run VQE on H4 + molecule, with ILC ansatz, JW qubit mapping, initial
MPCoons marked this conversation as resolved.
Show resolved Hide resolved
parameters, exact simulator.
"""

vqe_options = {"molecule": mol_H4_cation_sto3g, "ansatz": BuiltInAnsatze.ILC, "qubit_mapping": "jw",
"verbose": False}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

Expand Down
14 changes: 9 additions & 5 deletions tangelo/algorithms/variational/vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
from tangelo.toolboxes.operators import count_qubits, FermionOperator, qubitop_to_qubitham
from tangelo.toolboxes.qubit_mappings.mapping_transform import fermion_to_qubit_mapping
from tangelo.toolboxes.ansatz_generator.ansatz import Ansatz
from tangelo.toolboxes.ansatz_generator import UCCSD, RUCC, HEA, UpCCGSD, QMF, QCC, VSQS, UCCGD, VariationalCircuitAnsatz
from tangelo.toolboxes.ansatz_generator import UCCSD, RUCC, HEA, UpCCGSD, QMF, QCC, VSQS, UCCGD, ILC,\
VariationalCircuitAnsatz
from tangelo.toolboxes.ansatz_generator.penalty_terms import combined_penalty
from tangelo.toolboxes.post_processing.bootstrapping import get_resampled_frequencies
from tangelo.toolboxes.ansatz_generator.fermionic_operators import number_operator, spinz_operator, spin2_operator
Expand All @@ -47,6 +48,7 @@ class BuiltInAnsatze(Enum):
QCC = 6
VSQS = 7
UCCGD = 8
ILC = 9


class VQESolver:
Expand Down Expand Up @@ -112,11 +114,11 @@ def __init__(self, opt_dict):
if not (bool(self.molecule) ^ bool(self.qubit_hamiltonian)):
raise ValueError(f"A molecule OR qubit Hamiltonian object must be provided when instantiating {self.__class__.__name__}.")

# The QCC ansatz requires up_then_down=True when mapping="jw"
# The QCC & ILC ansatze require up_then_down=True when mapping="jw"
if isinstance(self.ansatz, BuiltInAnsatze):
if self.ansatz == BuiltInAnsatze.QCC and self.qubit_mapping.lower() == "jw" and not self.up_then_down:
warnings.warn("The QCC ansatz requires spin-orbital ordering to be all spin-up "
"first followed by all spin-down for the JW mapping.", RuntimeWarning)
if self.ansatz in (BuiltInAnsatze.QCC, BuiltInAnsatze.ILC) and self.qubit_mapping.lower() == "jw" and not self.up_then_down:
warnings.warn("Efficient generator screening for QCC-based ansatze requires spin-orbital ordering to be "
"all spin-up first followed by all spin-down for the JW mapping.", RuntimeWarning)
self.up_then_down = True

self.default_backend_options = default_backend_options
Expand Down Expand Up @@ -193,6 +195,8 @@ def build(self):
self.ansatz = VSQS(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
elif self.ansatz == BuiltInAnsatze.UCCGD:
self.ansatz = UCCGD(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
elif self.ansatz == BuiltInAnsatze.ILC:
self.ansatz = ILC(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
else:
raise ValueError(f"Unsupported ansatz. Built-in ansatze:\n\t{self.builtin_ansatze}")
elif not isinstance(self.ansatz, Ansatz):
Expand Down
1 change: 1 addition & 0 deletions tangelo/toolboxes/ansatz_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

from .vsqs import VSQS
from .ilc import ILC
from .qcc import QCC
from .qmf import QMF
from .uccsd import UCCSD
Expand Down
43 changes: 18 additions & 25 deletions tangelo/toolboxes/ansatz_generator/_qubit_cc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
from itertools import combinations

from tangelo.toolboxes.operators.operators import QubitOperator
from ._qubit_mf import get_op_expval
from tangelo.toolboxes.ansatz_generator._qubit_mf import get_op_expval


def construct_dis(pure_var_params, qubit_ham, qcc_deriv_thresh, verbose=False):
def construct_dis(qubit_ham, pure_var_params, deqcc_dtau_thresh):
"""Construct the DIS of QCC generators, which proceeds as follows:
1. Identify the flip indices of all Hamiltonian terms and group terms by flip indices.
2. Construct a representative generator using flip indices from each candidate DIS group
Expand All @@ -47,43 +47,36 @@ def construct_dis(pure_var_params, qubit_ham, qcc_deriv_thresh, verbose=False):
odd number of Y operators.

Args:
pure_var_params (numpy array of float): A purified QMF variational parameter set.
qubit_ham (QubitOperator): A qubit Hamiltonian.
qcc_deriv_thresh (float): Threshold value of |dEQCC/dtau| so that if |dEQCC/dtau| >=
qcc_deriv_thresh for a generator, add its candidate group to the DIS.
verbose (bool): Flag for QCC verbosity.
pure_var_params (numpy array of float): A purified QMF variational parameter set.
deqcc_dtau_thresh (float): Threshold for |dEQCC/dtau| so that a candidate group is added
to the DIS if |dEQCC/dtau| >= deqcc_dtau_thresh for a generator.

Returns:
list of list: the DIS of QCC generators.
"""

# Use a qubit Hamiltonian and purified QMF parameter set to construct the DIS
dis, dis_groups = [], get_dis_groups(pure_var_params, qubit_ham, qcc_deriv_thresh)
dis, dis_groups = [], get_dis_groups(qubit_ham, pure_var_params, deqcc_dtau_thresh)
if dis_groups:
if verbose:
print(f"The DIS contains {len(dis_groups)} unique generator group(s).\n")
for i, dis_group in enumerate(dis_groups):
for dis_group in dis_groups:
dis_group_idxs = [int(idxs) for idxs in dis_group[0].split(" ")]
dis_group_gens = get_gens_from_idxs(dis_group_idxs)
dis.append(dis_group_gens)
if verbose:
print(f"DIS group {i} | group size = {len(dis_group_gens)} | "
f"flip indices = {dis_group_idxs} | |dEQCC/dtau| = "
f"{abs(dis_group[1])} a.u.\n")
else:
raise ValueError(f"The DIS is empty: there are no candidate DIS groups where "
f"|dEQCC/dtau| >= {qcc_deriv_thresh} a.u. Terminate the QCC simulation.\n")
f"|dEQCC/dtau| >= {deqcc_dtau_thresh} a.u. Terminate simulation.\n")
return dis


def get_dis_groups(pure_var_params, qubit_ham, qcc_deriv_thresh):
def get_dis_groups(qubit_ham, pure_var_params, deqcc_dtau_thresh):
"""Construct unique DIS groups characterized by the flip indices and |dEQCC/dtau|.

Args:
pure_var_params (numpy array of float): A purified QMF variational parameter set.
qubit_ham (QubitOperator): A qubit Hamiltonian.
qcc_deriv_thresh (float): Threshold value of |dEQCC/dtau| so that if |dEQCC/dtau| >=
qcc_deriv_thresh for a generator, add its candidate group to the DIS.
pure_var_params (numpy array of float): A purified QMF variational parameter set.
deqcc_dtau_thresh (float): Threshold for |dEQCC/dtau| so that a candidate group is added
to the DIS if |dEQCC/dtau| >= deqcc_dtau_thresh for a generator.

Returns:
list of tuple: the DIS group flip indices (str) and signed value of dEQCC/dtau (float).
Expand All @@ -94,15 +87,15 @@ def get_dis_groups(pure_var_params, qubit_ham, qcc_deriv_thresh):
for qham_items in qubit_ham.terms.items())
flip_idxs = list(filter(None, (get_idxs_deriv(q_gen[0], *q_gen[1]) for q_gen in qham_gen)))

# Group Hamiltonian terms with the same flip indices and sum signed dEQCC/tau values
# Group Hamiltonian terms with the same flip indices and sum of the signed dEQCC/tau values
candidates = dict()
for idxs in flip_idxs:
deriv_old = candidates.get(idxs[0], 0.)
candidates[idxs[0]] = idxs[1] + deriv_old

# Return a sorted list of flip indices and signed dEQCC/dtau values for each DIS group
dis_groups = [idxs_deriv for idxs_deriv in candidates.items()
if abs(idxs_deriv[1]) >= qcc_deriv_thresh]
if abs(idxs_deriv[1]) >= deqcc_dtau_thresh]
return sorted(dis_groups, key=lambda deriv: abs(deriv[1]), reverse=True)


Expand All @@ -124,18 +117,18 @@ def get_idxs_deriv(qham_term, *qham_qmf_data):
"""

coef, pure_params = qham_qmf_data
idxs, gen_list, idxs_deriv = "", [], None
idxs, gen_tup, idxs_deriv = "", tuple(), None
for pauli_factor in qham_term:
# The indices of X and Y operators are flip indices
idx, pauli_op = pauli_factor
if "X" in pauli_op or "Y" in pauli_op:
gen = (idx, "Y") if idxs == "" else (idx, "X")
idxs = idxs + f" {idx}" if idxs != "" else f"{idx}"
gen_list.append(gen)
gen_tup += (gen, )
# Generators must have at least two flip indices
if len(gen_list) > 1:
if len(gen_tup) > 1:
qham_gen_comm = QubitOperator(qham_term, -1j * coef)
qham_gen_comm *= QubitOperator(tuple(gen_list), 1.)
qham_gen_comm *= QubitOperator(gen_tup, 1.)
deriv = get_op_expval(qham_gen_comm, pure_params).real
idxs_deriv = (idxs, deriv)
return idxs_deriv
Expand Down
Loading