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

Small fixes for ILC #346

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 9 additions & 9 deletions tangelo/algorithms/variational/iqcc_ilc_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,21 +256,21 @@ def _update_ilc_solver(self, e_ilc):
if self.compress_qubit_ham:
self.ilc_ansatz.qubit_ham.frobenius_norm_compression(self.compress_eps, n_qubits)

# set dis, acs, and var_params to none to rebuild the dis & acs and initialize new parameters
self.ilc_ansatz.dis = None
self.ilc_ansatz.acs = None
self.ilc_ansatz.var_params = None
self.ilc_ansatz.build_circuit()

self.vqe_solver.qubit_hamiltonian = self.ilc_ansatz.qubit_ham
self.vqe_solver.initial_var_params = self.ilc_ansatz.var_params

if self.iteration == self.max_ilc_iter:
self.terminate_ilc = True
self.final_optimal_qmf_params = optimal_qmf_var_params
self.final_optimal_ilc_params = optimal_ilc_var_params
if self.verbose:
print(f"Terminating the ILC-VQE solver after {self.max_ilc_iter} iterations.")
else:
# Set dis, acs, and var_params to None to rebuild the dis & acs and initialize new parameters
self.ilc_ansatz.dis = None
self.ilc_ansatz.acs = None
self.ilc_ansatz.var_params = None
self.ilc_ansatz.build_circuit()

self.vqe_solver.qubit_hamiltonian = self.ilc_ansatz.qubit_ham
self.vqe_solver.initial_var_params = self.ilc_ansatz.var_params

def _update_qcc_solver(self, e_iqcc_ilc):
"""Updates after the final QCC energy evaluation with the final ILC dressed
Expand Down
21 changes: 12 additions & 9 deletions tangelo/toolboxes/ansatz_generator/_qubit_ilc.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,16 @@ def gauss_elim_over_gf2(a_mat, b_vec=None):
return np.array(z_sln, dtype=int)


def get_ilc_params_by_diag(qubit_ham, ilc_gens, qmf_var_params):
def get_ilc_params_by_diag(qubit_ham, ilc_gens, qmf_var_params, return_energy=False):
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
"""Driver function that solves the generalized eigenvalue problem Hc = ESc required
to obtain the ground state coefficients (ILC parameters). These are subsequently recast
according to Appendix C of Ref. 1 in a form that is suitable for constructing ILC circuits.

Args:
qubit_ham (QubitOperator): the qubit Hamiltonian of the system.
ilc_gens (list of QubitOperator): the anticommuting set of ILC Pauli words.
qmf_var_params (array): The QMF variational parameters
return_energy (bool): Return the energy from the ILC diagonalization. Default False.

Returns:
list of float: the ILC parameters corresponding to the ACS of ILC generators
Expand Down Expand Up @@ -253,12 +255,12 @@ def get_ilc_params_by_diag(qubit_ham, ilc_gens, qmf_var_params):
qubit_overlap_mat[j, i] *= 1j

# Solve the generalized eigenvalue problem
_, subspace_coefs = scipy.linalg.eigh(a=qubit_ham_mat, b=qubit_overlap_mat, lower=True, driver="gvd")
energies, subspace_coefs = scipy.linalg.eigh(a=qubit_ham_mat, b=qubit_overlap_mat, lower=True, driver="gvd")

# Compute the ILC parameters using the ground state coefficients
gs_coefs = subspace_coefs[:, 0]
if gs_coefs[0].real > 0.:
gs_coefs *= -1.
if gs_coefs[0].real < 0.:
gs_coefs = -gs_coefs
denom_sum, ilc_var_params = 0., []
for i in range(2):
denom_sum += abs(gs_coefs[i])**2
Expand All @@ -269,7 +271,8 @@ def get_ilc_params_by_diag(qubit_ham, ilc_gens, qmf_var_params):
beta = np.arcsin(gs_coefs[i] / np.sqrt(denom_sum))
ilc_var_params.append(beta.real)
del ilc_gens[0]
return ilc_var_params
ilc_params = [-param for param in ilc_var_params]
return ilc_params if not return_energy else (ilc_params, energies[0])


def build_ilc_qubit_op_list(acs_gens, ilc_params):
Expand All @@ -288,9 +291,9 @@ def build_ilc_qubit_op_list(acs_gens, ilc_params):
"""

n_amps = len(ilc_params)
ilc_op_list = [-.5 * ilc_params[i] * acs_gens[i] for i in range(n_amps-1, 0, -1)]
ilc_op_list += [ilc_params[0] * acs_gens[0]]
ilc_op_list += [-.5 * ilc_params[i] * acs_gens[i] for i in range(1, n_amps)]
ilc_op_list = [-.5 * ilc_params[i] * acs_gens[i] for i in range(n_amps-1)]
ilc_op_list += [-ilc_params[n_amps-1] * acs_gens[n_amps-1]]
ilc_op_list += [-.5 * ilc_params[i] * acs_gens[i] for i in range(n_amps-2, -1, -1)]
return ilc_op_list


Expand Down Expand Up @@ -341,6 +344,6 @@ def ilc_op_dress(qubit_op, ilc_gens, ilc_params):
- .5j * sin_2tau * alphas[i] * commutator(qubit_op, ilc_gens[i])
for j in range(i+1, n_amps):
qop_dress += sin2_tau * alphas[i] * alphas[j] * (ilc_gens[i] * qubit_op * ilc_gens[j]
+ ilc_gens[j] * qubit_op * ilc_gens[i])
+ ilc_gens[j] * qubit_op * ilc_gens[i])
qop_dress.compress()
return qop_dress
2 changes: 1 addition & 1 deletion tangelo/toolboxes/ansatz_generator/ilc.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def prepare_reference_state(self):

def build_circuit(self, var_params=None):
"""Build and return the quantum circuit implementing the state preparation ansatz
(with currently specified initial_state and var_params). """
(with currently specified initial_state and var_params)."""

# Build the DIS or specify a list of generators; updates the number of QCC parameters
self._get_ilc_generators()
Expand Down
9 changes: 4 additions & 5 deletions tangelo/toolboxes/ansatz_generator/tests/test_ilc.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from tangelo.linq import get_backend
from tangelo.toolboxes.ansatz_generator.ilc import ILC
from tangelo.toolboxes.ansatz_generator._qubit_ilc import gauss_elim_over_gf2
from tangelo.toolboxes.ansatz_generator._qubit_ilc import gauss_elim_over_gf2, get_ilc_params_by_diag
from tangelo.toolboxes.operators.operators import QubitOperator
from tangelo.molecule_library import mol_H2_sto3g, mol_H4_cation_sto3g

Expand Down Expand Up @@ -148,7 +148,7 @@ def test_ilc_h2(self):

# The QMF and ILC parameters can both be specified; determined automatically otherwise.
qmf_var_params = [3.14159265e+00, 3.14159265e+00, -7.59061327e-12, 0.]
ilc_var_params = [1.12894599e-01]
ilc_var_params = [-1.12894599e-01]
var_params = qmf_var_params + ilc_var_params
ilc_ansatz.update_var_params(var_params)
# Assert energy returned is as expected for given parameters
Expand All @@ -175,13 +175,12 @@ def test_ilc_h4_cation(self):
qmf_var_params = [ 3.14159265e+00, -1.02576971e-11, 1.35522331e-11, 3.14159265e+00,
3.14159265e+00, -5.62116001e-11, -1.41419277e-11, -2.36789365e-11,
-5.53225030e-11, -3.56400157e-11, -2.61030058e-11, -3.55652002e-11]
ilc_var_params = [ 0.14001419, -0.10827113, 0.05840200, -0.12364925,
-0.07275071, -0.04703495, 0.02925292, 0.03145765]
ilc_var_params, energy_diag = get_ilc_params_by_diag(qubit_hamiltonian, ilc_ansatz.acs, np.array(qmf_var_params), return_energy=True)
var_params = qmf_var_params + ilc_var_params
# Assert energy returned is as expected for given parameters
ilc_ansatz.update_var_params(var_params)
energy = sim.get_expectation_value(qubit_hamiltonian, ilc_ansatz.circuit)
self.assertAlmostEqual(energy, -1.6379638, delta=1e-6)
self.assertAlmostEqual(energy_diag, energy, delta=1e-5)


if __name__ == "__main__":
Expand Down