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

Support freezing Hartree-Fock energies at each forging iteration #307

Merged
merged 36 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3cee1bd
Implement freezing hF energy value
caleb-johnson Jul 5, 2023
71af5c2
ruff
caleb-johnson Jul 5, 2023
1a2debe
init commit
caleb-johnson Jul 5, 2023
790ee93
save
caleb-johnson Jul 6, 2023
5ad4a38
tutorial is code for unit test. Ensure groundstate agrees with resear…
caleb-johnson Jul 6, 2023
e096083
ruff
caleb-johnson Jul 6, 2023
d418088
mypy and hf variable names
caleb-johnson Jul 8, 2023
d66cf84
black
caleb-johnson Jul 8, 2023
3d14e04
Add unit test
caleb-johnson Jul 8, 2023
804276b
improve docstring and add data
caleb-johnson Jul 8, 2023
36ce83d
Add section to forging explanatory
caleb-johnson Jul 10, 2023
7af31e9
Add release note and image
caleb-johnson Jul 10, 2023
08f98ca
feature instead of upgrade
caleb-johnson Jul 10, 2023
4250fc3
Update fixed-hartree-fock-447c33a956ffea84.yaml
caleb-johnson Jul 10, 2023
1f78313
Fix data filenames, and update comment
caleb-johnson Jul 10, 2023
35110be
black
caleb-johnson Jul 10, 2023
2eb206a
Update docs
caleb-johnson Jul 10, 2023
ad0b172
maxiter=0
caleb-johnson Jul 10, 2023
c66f135
Update hf_energy docstring. Update explanatory
caleb-johnson Jul 11, 2023
d7ad173
getters/setters coverage
caleb-johnson Jul 11, 2023
17a2f4c
Fix bug in asymmetric_bitstrings + set HF. Add test to cover bug
caleb-johnson Jul 11, 2023
e21d283
Include slow test
caleb-johnson Jul 11, 2023
7b76210
Run slow tests for coverage
caleb-johnson Jul 11, 2023
8e47c07
slow
caleb-johnson Jul 11, 2023
b8a1995
slow usage error
caleb-johnson Jul 11, 2023
21af043
ruff
caleb-johnson Jul 11, 2023
8f6fba9
cleanup
caleb-johnson Jul 12, 2023
36ad956
Fix bug in fixing HF energy with asymmetric bitstrings. Other bugfixes.
caleb-johnson Jul 12, 2023
8ea03b7
Remove unused args
caleb-johnson Jul 12, 2023
2f6b74e
Test to ensure our masks didnt interfere with schmidt matrix
caleb-johnson Jul 12, 2023
61cd6c8
revert run slow change. handle in separate pr
caleb-johnson Jul 12, 2023
924cc23
Add notes to test explaining hard-coded values
caleb-johnson Jul 20, 2023
93aa88c
Merge branch 'main' of github.com:Qiskit-Extensions/circuit-knitting-…
caleb-johnson Aug 14, 2023
a56a4e7
Update circuit_knitting/forging/entanglement_forging_ground_state_sol…
caleb-johnson Aug 14, 2023
2a06708
Update test_entanglement_forging_ground_state_solver.py
caleb-johnson Aug 14, 2023
06d08e7
black
caleb-johnson Aug 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def __init__(
backend_names: str | list[str] | None = None,
options: Options | list[Options] | None = None,
mo_coeff: np.ndarray | None = None,
hf_energy: float | None = None,
):
"""
Assign the necessary class variables and initialize any defaults.
Expand All @@ -143,6 +144,8 @@ def __init__(
backend_names: Backend name or list of backend names to use during parallel computation
options: Options or list of options to be applied to the backends
mo_coeff: Coefficients for converting an input problem to MO basis
hf_energy: If set, this energy will be used instead of calculating the Hartree-Fock
energy at each iteration.

Returns:
None
Expand All @@ -158,6 +161,7 @@ def __init__(
self.backend_names = backend_names # type: ignore
self.options = options
self._mo_coeff = mo_coeff
self._hf_energy = hf_energy
self._optimizer: Optimizer | MINIMIZER = optimizer or SPSA()

@property
Expand Down Expand Up @@ -246,6 +250,16 @@ def mo_coeff(self, mo_coeff: np.ndarray | None) -> None:
"""Set the coefficients for converting integrals to the MO basis."""
self._mo_coeff = mo_coeff

@property
def hf_energy(self) -> float | None:
"""Return the Hartree-Fock energy."""
return self._hf_energy

@hf_energy.setter
def hf_energy(self, hf_energy: float | None) -> None:
"""Set the Hartree-Fock energy."""
self._hf_energy = hf_energy

def solve(
self,
problem: ElectronicStructureProblem,
Expand Down Expand Up @@ -289,13 +303,14 @@ def solve(
backend_names = self._backend_names or ["ibmq_qasm_simulator"]
self._knitter = EntanglementForgingKnitter(
self._ansatz,
hf_energy=self._hf_energy,
service=self._service,
backend_names=backend_names,
options=self._options,
)
else:
self._knitter = EntanglementForgingKnitter(
self._ansatz, options=self._options
self._ansatz, hf_energy=self._hf_energy, options=self._options
)
self._history = EntanglementForgingHistory()
self._eval_count = 0
Expand Down
46 changes: 42 additions & 4 deletions circuit_knitting/forging/entanglement_forging_knitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class EntanglementForgingKnitter:
def __init__(
self,
ansatz: EntanglementForgingAnsatz,
hf_energy: float | None = None,
service: QiskitRuntimeService | None = None,
backend_names: str | list[str] | None = None,
options: Options | list[Options] | None = None,
Expand All @@ -48,6 +49,7 @@ def __init__(
Args:
ansatz: The container for the circuit structure and bitstrings to be used
(and generate the stateprep circuits)
hf_energy: If set, this energy will be used instead of calculating the Hartre e-Fock energy.
service: The service used to spawn Qiskit primitives and runtime jobs
backend_names: Names of the backends to use for calculating expectation values
options: Options to use with the backends
Expand All @@ -59,6 +61,7 @@ def __init__(
self._session_ids: list[str | None] | None = None
self._backend_names: list[str] | None = None
self._options: list[Options] | None = None
self._hf_energy = hf_energy
# Call constructors
self.backend_names = backend_names # type: ignore
self.options = options
Expand Down Expand Up @@ -141,6 +144,16 @@ def service(self, service: QiskitRuntimeService | None) -> None:
"""Change the service class field."""
self._service = service.active_account() if service is not None else service

@property
def hf_energy(self) -> float | None:
"""Return the Hartree-Fock energy."""
return self._hf_energy

@hf_energy.setter
def hf_energy(self, hf_energy: float | None) -> None:
"""Set the Hartree-Fock energy."""
self._hf_energy = hf_energy

def __call__(
self,
ansatz_parameters: Sequence[float],
Expand Down Expand Up @@ -256,6 +269,7 @@ def __call__(
tensor_pauli_list,
superposition_ansatze_partition,
superposition_pauli_list,
self._hf_energy,
service_args,
backend_name,
options,
Expand All @@ -282,10 +296,25 @@ def __call__(
)
self._session_ids[i] = job_id

if self._hf_energy is not None:
nans_u = np.empty(np.shape(tensor_expvals[0]))
nans_u[:] = np.nan
if not self._ansatz.bitstrings_are_symmetric:
num_tensor_terms = int(np.shape(tensor_expvals)[0] / 2)
nans_v = np.empty(np.shape(tensor_expvals[num_tensor_terms]))
nans_v[:] = np.nan
tensor_expvals.insert(num_tensor_terms, nans_v)
tensor_expvals.insert(0, nans_u)

# Compute the Schmidt matrix
h_schmidt = self._compute_h_schmidt(
forged_operator, np.array(tensor_expvals), np.array(superposition_expvals)
)

# Hard-code the Hartree-Fock energy, if desired
caleb-johnson marked this conversation as resolved.
Show resolved Hide resolved
if self._hf_energy is not None:
h_schmidt[0, 0] = self._hf_energy

evals, evecs = np.linalg.eigh(h_schmidt)
schmidt_coeffs = evecs[:, 0]
energy = evals[0]
Expand Down Expand Up @@ -569,10 +598,11 @@ def _estimate_expvals(
tensor_paulis: list[Pauli],
superposition_ansatze: list[QuantumCircuit],
superposition_paulis: list[Pauli],
service_args: dict[str, Any] | None = None,
backend_name: str | None = None,
options: Options | None = None,
session_id: str | None = None,
hf_energy: float | None,
service_args: dict[str, Any] | None,
backend_name: str | None,
options: Options | None,
session_id: str | None,
) -> tuple[list[np.ndarray], list[np.ndarray], str | None]:
"""Run quantum circuits to generate the expectation values.

Expand All @@ -587,6 +617,7 @@ def _estimate_expvals(
superposition_ansatze: The circuits with different Schmidt coefficients
superposition_paulis: The pauli operators to measure and calculate
the expectation values from for the circuits with different Schmidt coefficients
hf_energy: The Hartree-Fock energy to be hard-coded in the Schmidt matrix
service_args: The service account used to spawn Qiskit primitives
backend_name: The backend to use to evaluate the grouped experiments
options: The options to use with the backend
Expand All @@ -595,6 +626,10 @@ def _estimate_expvals(
Returns:
The expectation values for the tensor circuits and superposition circuits
"""
# Ignore HF energy calculation. We will hard-code it later.
caleb-johnson marked this conversation as resolved.
Show resolved Hide resolved
if hf_energy is not None:
tensor_ansatze = tensor_ansatze[1:]

ansatz_t: list[QuantumCircuit] = []
observables_t: list[Pauli] = []
for i, circuit in enumerate(tensor_ansatze):
Expand Down Expand Up @@ -646,6 +681,9 @@ def _estimate_expvals(
# Post-process the results to get our expectation values in the right format
num_tensor_expvals = len(tensor_ansatze) * len(tensor_paulis)
estimator_results_t = results[:num_tensor_expvals]
if hf_energy is not None:
for _ in enumerate(tensor_paulis):
caleb-johnson marked this conversation as resolved.
Show resolved Hide resolved
np.insert(estimator_results_t, 0, np.nan)
estimator_results_s = results[num_tensor_expvals:]

tensor_expval_list = list(
Expand Down