Skip to content

Commit

Permalink
added vsqs ansatz
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesB-1qbit committed Jan 10, 2022
1 parent c4c9190 commit d29c5bb
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/github_actions_automated_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
pip install qiskit==0.33.1 # Due to strange behaviour of noise model
pip install qulacs
pip install amazon-braket-sdk
pip install cirq==0.12.0
pip install cirq
pip install projectq
if: always()

Expand Down
26 changes: 26 additions & 0 deletions tangelo/algorithms/variational/tests/test_vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import unittest
import numpy as np

Expand Down Expand Up @@ -137,6 +138,31 @@ def test_simulate_qcc_h2(self):
energy = vqe_solver.simulate()
self.assertAlmostEqual(energy, -1.137270, delta=1e-4)

def test_simulate_vsqs_h2(self):
"""Run VQE on H2 molecule, with vsqs ansatz, JW qubit mapping, exact simulator for both molecule input and
qubit_hamiltonian/hini/reference_state input
"""
vqe_options = {"molecule": mol_H2_sto3g, "ansatz": BuiltInAnsatze.VSQS, "qubit_mapping": "jw",
"verbose": True, "ansatz_options": {"intervals": 3, "time": 3}}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

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

qubit_hamiltonian = vqe_solver.qubit_hamiltonian
hini = vqe_solver.ansatz.hini
reference_state = vqe_solver.ansatz.prepare_reference_state()

vqe_options = {"molecule": None, "qubit_hamiltonian": qubit_hamiltonian, "ansatz": BuiltInAnsatze.VSQS, "qubit_mapping": "jw",
"ansatz_options": {"intervals": 3, "time": 3, "qubit_hamiltonian": qubit_hamiltonian,
"hini": hini, "reference_state": reference_state}}
vqe_solver = VQESolver(vqe_options)
vqe_solver.build()

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

def test_simulate_h2_qiskit(self):
"""Run VQE on H2 molecule, with UCCSD ansatz, JW qubit mapping, initial
parameters, exact qiskit simulator.
Expand Down
11 changes: 10 additions & 1 deletion tangelo/algorithms/variational/vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from tangelo.toolboxes.ansatz_generator.upccgsd import UpCCGSD
from tangelo.toolboxes.ansatz_generator.qmf import QMF
from tangelo.toolboxes.ansatz_generator.qcc import QCC
from tangelo.toolboxes.ansatz_generator.vsqs import VSQS
from tangelo.toolboxes.ansatz_generator.variational_circuit import VariationalCircuitAnsatz
from tangelo.toolboxes.ansatz_generator.penalty_terms import combined_penalty
from tangelo.toolboxes.post_processing.bootstrapping import get_resampled_frequencies
Expand All @@ -50,6 +51,7 @@ class BuiltInAnsatze(Enum):
UpCCGSD = 4
QMF = 5
QCC = 6
VSQS = 7


class VQESolver:
Expand Down Expand Up @@ -186,13 +188,20 @@ def build(self):
self.ansatz = QMF(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
elif self.ansatz == BuiltInAnsatze.QCC:
self.ansatz = QCC(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
elif self.ansatz == BuiltInAnsatze.VSQS:
self.ansatz = VSQS(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):
raise TypeError(f"Invalid ansatz dataype. Expecting instance of Ansatz class, or one of built-in options:\n\t{self.builtin_ansatze}")

# Building with a qubit Hamiltonian.
elif not isinstance(self.ansatz, Ansatz):
elif not isinstance(self.ansatz, Ansatz) or self.ansatz not in [BuiltInAnsatze.HEA, BuiltInAnsatze.VSQS]:
if self.ansatz == BuiltInAnsatze.HEA:
self.ansatz = HEA(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
elif self.ansatz == BuiltInAnsatze.VSQS:
self.ansatz = VSQS(self.molecule, self.qubit_mapping, self.up_then_down, **self.ansatz_options)
else:
raise TypeError(f"Invalid ansatz dataype. Expecting a custom Ansatz (Ansatz class).")

# Set ansatz initial parameters (default or use input), build corresponding ansatz circuit
Expand Down
13 changes: 10 additions & 3 deletions tangelo/toolboxes/ansatz_generator/ansatz_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def exp_pauliword_to_gates(pauli_word, coef, variational=True, control=None):


def get_exponentiated_qubit_operator_circuit(qubit_op, time=1., variational=False, trotter_order=1, control=None,
return_phase=False):
return_phase=False, pauli_order=None):
"""Generate the exponentiation of a qubit operator in first- or second-order Trotterized form.
The algorithm is described in Whitfield 2010 https://arxiv.org/pdf/1001.3855.pdf
Expand All @@ -94,12 +94,19 @@ def get_exponentiated_qubit_operator_circuit(qubit_op, time=1., variational=Fals
variational (bool) : Whether the coefficients are variational
trotter_order (int): order of trotter approximation, only 1 or 2 are supported.
return_phase (bool): Return the global-phase generated
pauli_order (list): The desired pauli_word order defined as a list with elements (pauli_word, coeff)
with corresponding dictionary elements pauli_word: coeff in QubitOperator terms.items()
Returns:
Circuit: circuit corresponding to exponentiation of qubit operator
phase : The global phase of the time evolution if return_phase=True else not included
"""
pauli_words = list(qubit_op.terms.items())
if pauli_order is None:
pauli_words = list(qubit_op.terms.items())
elif isinstance(pauli_order, list):
pauli_words = deepcopy(pauli_order)
else:
raise ValueError("ordered terms must be a list with elements (keys, values) of qubit_op.terms.items()")

if trotter_order > 2:
raise ValueError(f"Trotter order of >2 is not supported currently in Tangelo.")
Expand All @@ -118,7 +125,7 @@ def get_exponentiated_qubit_operator_circuit(qubit_op, time=1., variational=Fals
phase = 1.
exp_pauli_word_gates = list()
for i in range(trotter_order):
if i == 0:
if i == 1:
pauli_words.reverse()
for pauli_word, coef in pauli_words:
if pauli_word: # identity terms do not contribute to evolution outside of a phase
Expand Down
116 changes: 116 additions & 0 deletions tangelo/toolboxes/ansatz_generator/tests/test_vsqs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright 2021 Good Chemistry Company.
#
# 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.

import unittest
import numpy as np
import os
from openfermion import load_operator

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

# For openfermion.load_operator function.
pwd_this_test = os.path.dirname(os.path.abspath(__file__))


class VSQSTest(unittest.TestCase):

def test_vsqs_set_var_params(self):
"""Verify behavior of set_var_params for different inputs (list, numpy array).
MP2 have their own tests.
"""

vsqs_ansatz = VSQS(mol_H2_sto3g)

two_ones = np.ones((2,))

vsqs_ansatz.set_var_params([1., 1.])
np.testing.assert_array_almost_equal(vsqs_ansatz.var_params, two_ones, decimal=6)

vsqs_ansatz.set_var_params(np.array([1., 1.]))
np.testing.assert_array_almost_equal(vsqs_ansatz.var_params, two_ones, decimal=6)

def test_vsqs_incorrect_number_var_params(self):
"""Return an error if user provide incorrect number of variational
parameters.
"""

vsqs_ansatz = VSQS(mol_H2_sto3g)

self.assertRaises(ValueError, vsqs_ansatz.set_var_params, np.array([1., 1., 1., 1.]))

def test_vsqs_H2(self):
"""Verify closed-shell VSQS functionalities for H2."""

# Build circuit
vsqs_ansatz = VSQS(mol_H2_sto3g, intervals=3, time=3)
vsqs_ansatz.build_circuit()

# Build qubit hamiltonian for energy evaluation
qubit_hamiltonian = jordan_wigner(mol_H2_sto3g.fermionic_hamiltonian)

# Assert energy returned is as expected for given parameters
sim = Simulator()
vsqs_ansatz.update_var_params([0.66666667, 0.9698286, 0.21132472, 0.6465473])
energy = sim.get_expectation_value(qubit_hamiltonian, vsqs_ansatz.circuit)
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"""

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 circuit
vsqs_ansatz = VSQS(qubit_hamiltonian=qubit_hamiltonian, hini=initial_hamiltonian, reference_state=reference_state,
intervals=5, time=5, trotter_order=2)
vsqs_ansatz.build_circuit()

# Assert energy returned is as expected for given parameters
sim = Simulator()
vsqs_ansatz.update_var_params(var_params)
energy = sim.get_expectation_value(qubit_hamiltonian, vsqs_ansatz.circuit)
self.assertAlmostEqual(energy, -0.85425, delta=1e-4)

def test_vsqs_H2_with_hnav(self):
"""Verify closed-shell VSQS functionalities for H2 with navigator hamiltonian"""
navigator_hamiltonian = (QubitOperator('X0 Y1', 0.03632537110234512) + QubitOperator('Y0 X1', 0.03632537110234512)
+ QubitOperator('Y0', 2.e-5) + QubitOperator('Y1', 2.e-5))

# Build qubit hamiltonian for energy evaluation
qubit_hamiltonian = symmetry_conserving_bravyi_kitaev(mol_H2_sto3g.fermionic_hamiltonian, 4, 2, False, 0)

# Build circuit
vsqs_ansatz = VSQS(mol_H2_sto3g, intervals=2, time=1, mapping='scbk', up_then_down=True, trotter_order=2,
hnav=navigator_hamiltonian)
vsqs_ansatz.build_circuit()

# Assert energy returned is as expected for given parameters
sim = Simulator()
vsqs_ansatz.update_var_params([0.50000001, -0.02494214, 3.15398767])
energy = sim.get_expectation_value(qubit_hamiltonian, vsqs_ansatz.circuit)
self.assertAlmostEqual(energy, -1.1372701255155757, delta=1e-6)


if __name__ == "__main__":
unittest.main()
Loading

0 comments on commit d29c5bb

Please sign in to comment.