diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 68fcf8c2..1b477cf8 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -57,7 +57,7 @@ jobs: # RECIRQ_IMPORT_FAILSAFE: skip tests on unsupported Cirq configurations # EXPORT_OMP_NUM_THREADS: pyscf has poor openmp performance which slows down qcqmc tests. export OMP_NUM_THREADS=1 - RECIRQ_IMPORT_FAILSAFE=y pytest -v + RECIRQ_IMPORT_FAILSAFE=y pytest -v --skipslow nbformat: name: Notebook formatting diff --git a/recirq/qcqmc/conftest.py b/conftest.py similarity index 91% rename from recirq/qcqmc/conftest.py rename to conftest.py index a216f21c..7b325ba4 100644 --- a/recirq/qcqmc/conftest.py +++ b/conftest.py @@ -102,3 +102,12 @@ def fixture_8_qubit_ham_and_trial_wf( ) return fixture_8_qubit_ham, trial_wf + + +def pytest_addoption(parser): + parser.addoption("--skipslow", action="store_true", help="skips slow tests") + + +def pytest_runtest_setup(item): + if "slow" in item.keywords and item.config.getvalue("skipslow"): + pytest.skip("skipped because of --skipslow option") diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..5c8e5e83 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + slow: marks tests as slow (deselect with '--skipslow') diff --git a/recirq/qcqmc/__init__.py b/recirq/qcqmc/__init__.py index bbae0f6f..f08f24e0 100644 --- a/recirq/qcqmc/__init__.py +++ b/recirq/qcqmc/__init__.py @@ -16,10 +16,14 @@ from cirq.protocols.json_serialization import DEFAULT_RESOLVERS, ObjectFactory +from .blueprint import (BlueprintData, BlueprintParamsRobustShadow, + BlueprintParamsTrialWf) from .fermion_mode import FermionicMode -from .hamiltonian import HamiltonianData, HamiltonianFileParams, PyscfHamiltonianParams +from .hamiltonian import (HamiltonianData, HamiltonianFileParams, + PyscfHamiltonianParams) from .layer_spec import LayerSpec -from .trial_wf import PerfectPairingPlusTrialWavefunctionParams, TrialWavefunctionData +from .trial_wf import (PerfectPairingPlusTrialWavefunctionParams, + TrialWavefunctionData) @lru_cache() @@ -43,6 +47,9 @@ def _resolve_json(cirq_type: str) -> Optional[ObjectFactory]: LayerSpec, PerfectPairingPlusTrialWavefunctionParams, TrialWavefunctionData, + BlueprintParamsTrialWf, + BlueprintParamsRobustShadow, + BlueprintData, ] }.get(cirq_type, None) diff --git a/recirq/qcqmc/blueprint.py b/recirq/qcqmc/blueprint.py new file mode 100644 index 00000000..8cdd1791 --- /dev/null +++ b/recirq/qcqmc/blueprint.py @@ -0,0 +1,324 @@ +# Copyright 2024 Google +# +# 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 +# +# https://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 itertools +from typing import Dict, Iterable, Iterator, List, Optional, Sequence, Tuple, Union + +import attrs +import cirq +import numpy as np +import quaff + +from recirq.qcqmc import config, data, trial_wf, for_refactor + +BlueprintParams = Union["BlueprintParamsTrialWf", "BlueprintParamsRobustShadow"] + + +def apply_optimizer_suite_0(circuit: cirq.Circuit) -> cirq.Circuit: + """A circuit optimization routine that tries to merge gates. + + Args: + circuit: The circuit to optimize + + Returns: + The gate optimized circuit. + """ + + circuit = cirq.expand_composite(circuit) + circuit = cirq.align_left(circuit) + circuit = cirq.drop_empty_moments(circuit) + + return circuit + + +def _to_tuple_of_tuples( + x: Iterable[Iterable[cirq.Qid]], +) -> Tuple[Tuple[cirq.Qid, ...], ...]: + # required for dataclass type conversion + return tuple(tuple(_) for _ in x) + + +def _to_tuple(x: Iterable[cirq.Circuit]) -> Tuple[cirq.Circuit, ...]: + # required for dataclass type conversion + return tuple(x) + + +def _get_truncated_cliffords( + n_cliffords: int, qubit_partition: Sequence[Sequence[cirq.Qid]], seed: int +) -> Iterator[List[quaff.TruncatedCliffordGate]]: + """Gets the gates (not the circuits) for applying the random circuit for shadow tomography. + + Args: + n_cliffords: The number of random cliffords to use during shadow tomography. + qubit_partition: For shadow tomography, we partition the qubits into these + disjoint partitions. For example, we can partition into single-qubit partitions + and sample from random single-qubit cliffords or put all qubits in one partition + and sample from random n-qubit cliffords. + seed: A random number seed. + + Returns: + An iterator to a list of truncated clifford gates. + """ + rng = np.random.default_rng(seed) + + for _ in range(n_cliffords): + yield [ + quaff.TruncatedCliffordGate.random(len(part), rng) + for part in qubit_partition + ] + + +def _get_resolvers( + n_cliffords: int, qubit_partition: Sequence[Sequence[cirq.Qid]], seed: int +) -> Iterator[Dict[str, np.integer]]: + """Gets the resolvers for a parameterized shadow tomography circuit. + + These are used in running the experiment / simulation. + + Args: + n_cliffords: The number of random cliffords to use during shadow tomography. + qubit_partition: For shadow tomography, we partition the qubits into these + disjoint partitions. For example, we can partition into single-qubit partitions + and sample from random single-qubit cliffords or put all qubits in one partition + and sample from random n-qubit cliffords. + Returns: + An iterator to a circuit resolver. + """ + truncated_cliffords = _get_truncated_cliffords( + n_cliffords=n_cliffords, qubit_partition=qubit_partition, seed=seed + ) + + for clifford_set in truncated_cliffords: + yield quaff.get_truncated_cliffords_resolver(clifford_set) + + +@attrs.frozen +class BlueprintParamsTrialWf(data.Params): + """Class for storing the parameters that specify a BlueprintData. + + This stage of the experiment concerns itself with the Hardware-specific concerns + of compilation and shadow tomography implementation. + + Args: + name: `Params` name for this experiment. + trial_wf_params: A back-reference to the `TrialWavefunctionParams` + used in this experiment. + n_cliffords: The number of random cliffords to use during shadow tomography. + qubit_partition: For shadow tomography, we partition the qubits into these + disjoint partitions. For example, we can partition into single-qubit partitions + and sample from random single-qubit cliffords or put all qubits in one partition + and sample from random n-qubit cliffords. + seed: The random seed used for clifford generation. + optimizer_suite: How to compile/optimize circuits for running on real devices. Can + be `0` or `1` corresponding to the functions `apply_optimizer_suite_x`. + path_prefix: A path string to prefix the blueprint output directory with. + """ + + name: str + trial_wf_params: trial_wf.TrialWavefunctionParams + n_cliffords: int + qubit_partition: Tuple[Tuple[cirq.Qid, ...], ...] = attrs.field( + converter=_to_tuple_of_tuples + ) + seed: int = 0 + optimizer_suite: int = 0 + path_prefix: str = "" + + @property + def path_string(self) -> str: + return self.path_prefix + config.OUTDIRS.DEFAULT_BLUEPRINT_DIRECTORY + self.name + + @property + def qubits_jordan_wigner_order(self) -> Tuple[cirq.GridQubit, ...]: + """A helper that gets the qubits for this Blueprint.""" + return self.trial_wf_params.qubits_jordan_wigner_ordered + + @property + def qubits_linearly_connected(self) -> Tuple[cirq.GridQubit, ...]: + """A helper that gets the qubits for this Blueprint.""" + return self.trial_wf_params.qubits_linearly_connected + + @property + def qubits(self) -> Tuple[cirq.Qid, ...]: + return self.trial_wf_params.qubits_linearly_connected + + def _json_dict_(self): + simple_dict = attrs.asdict(self) + simple_dict["trial_wf_params"] = self.trial_wf_params + return simple_dict + + +@attrs.frozen +class BlueprintData(data.Data): + """Data resulting from the "Blueprint" phase of the experiment. + + This stage of the experiment concerns itself with the Hardware-specific concerns + of compilation and shadow tomography implementation. + + Args: + params: A back-reference to the `BlueprintParams` used to create this `Data`. + compiled_circuit: A circuit suitable for running on the hardware including the + ansatz preparation segment and shadow-tomography rotations (i.e. layers of + cliffords). Its clifford layers are parameterized for efficient execution, + so you must combine this with `resolvers`. + parameterized_clifford_circuits: A parameterized circuit that corresponds to + just the Clifford part of the shadow tomography circuit. Useful for + inverting the channel when combined with resolvers. + resolvers: A list of `cirq.ParamResolver` corresponding to the (outer) list of + random cliffords. When combined with the parameterized `compiled_circuit` and + `cirq.Sampler.run_sweep`, this will execute all the different random clifford + circuits. + """ + + params: BlueprintParams + compiled_circuit: cirq.Circuit + parameterized_clifford_circuits: Tuple[cirq.Circuit] = attrs.field( + converter=_to_tuple + ) + resolvers: List[cirq.ParamResolverOrSimilarType] + + def _json_dict_(self): + simple_dict = attrs.asdict(self) + simple_dict["params"] = self.params + + @property + def resolved_clifford_circuits(self) -> Iterator[Tuple[cirq.Circuit, ...]]: + """An iterator of resolved clifford circuits.""" + for resolver in self.resolvers: + yield tuple( + cirq.resolve_parameters(clifford, resolver) + for clifford in self.parameterized_clifford_circuits + ) + + @classmethod + def build_blueprint_from_base_circuit( + cls, params: BlueprintParams, *, base_circuit: cirq.AbstractCircuit + ) -> "BlueprintData": + """Builds a BlueprintData from BlueprintParams. + + Args: + params: The experiment blueprint parameters. + base_circuit: The circuit to shadow tomographize. + + Returns: + A constructed BlueprintData object. + """ + resolvers = list( + _get_resolvers(params.n_cliffords, params.qubit_partition, params.seed) + ) + + parameterized_clifford_ops: Iterable[cirq.OP_TREE] = ( + quaff.get_parameterized_truncated_cliffords_ops(params.qubit_partition) + ) + + parameterized_clifford_circuits = tuple( + cirq.expand_composite( + cirq.Circuit(ops), no_decomp=for_refactor.is_expected_elementary_cirq_op + ) + for ops in parameterized_clifford_ops + ) + parameterized_clifford_circuit = sum( + parameterized_clifford_circuits, cirq.Circuit() + ) + + compiled_circuit = cirq.Circuit([base_circuit, parameterized_clifford_circuit]) + + circuit_with_measurement = compiled_circuit + cirq.Circuit( + cirq.measure(*params.qubits, key="all") + ) + + apply_optimizer_suite = {0: apply_optimizer_suite_0}[params.optimizer_suite] + + optimized_circuit = apply_optimizer_suite(circuit_with_measurement) + + return BlueprintData( + params=params, + compiled_circuit=optimized_circuit, + parameterized_clifford_circuits=parameterized_clifford_circuits, + resolvers=resolvers, # type: ignore + ) + + @classmethod + def build_blueprint_from_dependencies( + cls, + params: BlueprintParams, + dependencies: Optional[Dict[data.Params, data.Data]] = None, + ) -> "BlueprintData": + """Builds a BlueprintData from BlueprintParams using the dependency-injection workflow system. + + Args: + params: The blueprint parameters + dependencies: The dependencies used to construct the base circuit. If + BlueprintParamsRobustShadow are passed for params then the + base_circuit used for shadow tomography will be an empty circuit. + Otherwise it will be built from the trial wavefunction's + superposition circuit. + + Returns: + A constructed BlueprintData object. + """ + if isinstance(params, BlueprintParamsRobustShadow): + base_circuit = cirq.Circuit() + elif isinstance(params, BlueprintParamsTrialWf): + assert dependencies is not None, "Provide trial_wf" + assert params.trial_wf_params in dependencies, "trial_wf dependency" + trial_wf_inst = dependencies[params.trial_wf_params] + assert isinstance(trial_wf_inst, trial_wf.TrialWavefunctionData) + base_circuit = trial_wf_inst.superposition_circuit + else: + raise ValueError(f"Bad param type {type(params)}") + + return BlueprintData.build_blueprint_from_base_circuit( + params=params, base_circuit=base_circuit + ) + + +@attrs.frozen(repr=False) +class BlueprintParamsRobustShadow(data.Params): + """Class for storing the parameters that specify a BlueprintData. + + Args: + n_cliffords: The number of random cliffords to use during shadow tomography. + qubit_partition: For shadow tomography, we partition the qubits into these + disjoint partitions. For example, we can partition into single-qubit partitions + and sample from random single-qubit cliffords or put all qubits in one partition + and sample from random n-qubit cliffords. + seed: A random number seed. + optimizer_suite: The optimizer suite to use. + """ + + name: str + n_cliffords: int + qubit_partition: Tuple[Tuple[cirq.Qid, ...], ...] + seed: int = 0 + optimizer_suite: int = 0 + + def __post_init__(self): + """A little helper to ensure that tuples end up as tuples after loading.""" + object.__setattr__( + self, + "qubit_partition", + tuple(tuple(inner for inner in thing) for thing in self.qubit_partition), + ) + + @property + def path_string(self) -> str: + return config.OUTDIRS.DEFAULT_BLUEPRINT_DIRECTORY + self.name + + @property + def qubits(self) -> Tuple[cirq.Qid, ...]: + """The cirq qubits.""" + return tuple(itertools.chain(*self.qubit_partition)) + + def _json_dict_(self): + return attrs.asdict(self) diff --git a/recirq/qcqmc/blueprint_test.py b/recirq/qcqmc/blueprint_test.py new file mode 100644 index 00000000..93c9906e --- /dev/null +++ b/recirq/qcqmc/blueprint_test.py @@ -0,0 +1,252 @@ +# Copyright 2024 Google +# +# 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 +# +# https://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. +from typing import Iterable, Tuple + +import cirq +import numpy as np +import pytest +import quaff + +from recirq.qcqmc.blueprint import ( + BlueprintParamsTrialWf, + _get_truncated_cliffords, + BlueprintData +) +from recirq.qcqmc.hamiltonian import HamiltonianData, HamiltonianFileParams +from recirq.qcqmc.qubit_maps import get_qubits_a_b_reversed +from recirq.qcqmc.trial_wf import TrialWavefunctionData, TrialWavefunctionParams + + +class FakeTrialWfParams(TrialWavefunctionParams): + @property + def bitstrings(self) -> Iterable[Tuple[bool, ...]]: + raise NotImplementedError() + + @property + def path_string(self) -> str: + raise NotImplementedError() + + @property + def qubits_jordan_wigner_ordered(self) -> Tuple[cirq.GridQubit, ...]: + return tuple(cirq.GridQubit.rect(4, 1)) + + @property + def qubits_linearly_connected(self) -> Tuple[cirq.GridQubit, ...]: + return tuple(cirq.GridQubit.rect(4, 1)) + + +def test_build_blueprint_from_base_circuit(): + trial_wf_params = FakeTrialWfParams( + name="fake", + hamiltonian_params=HamiltonianFileParams("fake", "fake", 0, 0), + ) + blueprint_params = BlueprintParamsTrialWf( + name="blueprint_test", + trial_wf_params=trial_wf_params, + n_cliffords=10, + qubit_partition=tuple( + (q,) for q in trial_wf_params.qubits_jordan_wigner_ordered + ), + seed=1, + ) + bp_data = BlueprintData.build_blueprint_from_base_circuit( + blueprint_params, base_circuit=cirq.Circuit() + ) + assert isinstance(bp_data.compiled_circuit, cirq.AbstractCircuit) + assert len(bp_data.resolvers) == 10 + + +def test_small_blueprint( + fixture_4_qubit_ham_and_trial_wf: Tuple[HamiltonianData, TrialWavefunctionData] +): + _, trial_wf_data = fixture_4_qubit_ham_and_trial_wf + trial_wf_params = trial_wf_data.params + import attrs + + for k, v in attrs.asdict((trial_wf_params)).items(): + print(k, v) + + blueprint_params = BlueprintParamsTrialWf( + name="blueprint_test", + trial_wf_params=trial_wf_params, + n_cliffords=5, + qubit_partition=(tuple(get_qubits_a_b_reversed(n_orb=trial_wf_params.n_orb)),), + seed=1, + ) + blueprint = BlueprintData.build_blueprint_from_dependencies( + blueprint_params, dependencies={trial_wf_params: trial_wf_data} + ) + + assert len(list(blueprint.resolvers)) == 5 + + resolved_circuits = list(blueprint.resolved_clifford_circuits) + assert len(resolved_circuits) == 5 + for circuit_tuple in resolved_circuits: + assert len(circuit_tuple) == 1 + for circuit, qubits in zip(circuit_tuple, blueprint_params.qubit_partition): + assert len(circuit.all_qubits()) == len(qubits) + assert set(circuit.all_qubits()) == set(qubits) + + +def test_small_blueprint_2( + fixture_4_qubit_ham_and_trial_wf: Tuple[HamiltonianData, TrialWavefunctionData] +): + _, trial_wf_data = fixture_4_qubit_ham_and_trial_wf + trial_wf_params = trial_wf_data.params + + blueprint_params = BlueprintParamsTrialWf( + name="blueprint_test_2", + trial_wf_params=trial_wf_params, + n_cliffords=5, + qubit_partition=tuple( + (qubit,) for qubit in trial_wf_params.qubits_jordan_wigner_ordered + ), + seed=1, + ) + + blueprint = BlueprintData.build_blueprint_from_dependencies( + blueprint_params, dependencies={trial_wf_params: trial_wf_data} + ) + + assert len(list(blueprint.resolvers)) == 5 + + resolved_circuits = list(blueprint.resolved_clifford_circuits) + assert len(resolved_circuits) == 5 + for circuit_tuple in resolved_circuits: + assert len(circuit_tuple) == 4 + for circuit, qubits in zip(circuit_tuple, blueprint_params.qubit_partition): + assert len(circuit.all_qubits()) == len(qubits) + assert set(circuit.all_qubits()) == set(qubits) + + +@pytest.mark.slow() +def test_medium( + fixture_8_qubit_ham_and_trial_wf: Tuple[HamiltonianData, TrialWavefunctionData] +): + _, trial_wf_data = fixture_8_qubit_ham_and_trial_wf + trial_wf_params = trial_wf_data.params + + blueprint_params = BlueprintParamsTrialWf( + name="blueprint_test_medium", + trial_wf_params=trial_wf_params, + n_cliffords=3, + qubit_partition=( + tuple(qubit for qubit in trial_wf_params.qubits_jordan_wigner_ordered), + ), + seed=1, + ) + + blueprint = BlueprintData.build_blueprint_from_dependencies( + blueprint_params, dependencies={trial_wf_params: trial_wf_data} + ) + + assert len(list(blueprint.resolvers)) == 3 + + resolved_circuits = list(blueprint.resolved_clifford_circuits) + assert len(resolved_circuits) == 3 + for circuit_tuple in resolved_circuits: + print(len(circuit_tuple), len(circuit_tuple[0])) + assert len(circuit_tuple) == 1 + for circuit, qubits in zip(circuit_tuple, blueprint_params.qubit_partition): + assert len(circuit.all_qubits()) == len(qubits) + assert set(circuit.all_qubits()) == set(qubits) + + +@pytest.mark.slow +@pytest.mark.parametrize("seed", range(0, 3, 2)) +def test_quaff_respects_seed(seed): + n_cliffords = 500 + + rng_1a = np.random.default_rng(seed) + rng_1b = np.random.default_rng(seed) + rng_2a = np.random.default_rng(seed + 1) + rng_2b = np.random.default_rng(seed + 1) + + qubits = cirq.LineQubit.range(4) + qubit_partition = ((qubits[0], qubits[1]), (qubits[2], qubits[3])) + + cirq.Circuit(quaff.get_parameterized_truncated_cliffords_ops(qubit_partition)) + + truncated_cliffords_1a = [ + [ + quaff.TruncatedCliffordGate.random(len(qubits), rng_1a) + for qubits in qubit_partition + ] + for _ in range(n_cliffords) + ] + + truncated_cliffords_1b = [ + [ + quaff.TruncatedCliffordGate.random(len(qubits), rng_1b) + for qubits in qubit_partition + ] + for _ in range(n_cliffords) + ] + + truncated_cliffords_2a = [ + [ + quaff.TruncatedCliffordGate.random(len(qubits), rng_2a) + for qubits in qubit_partition + ] + for _ in range(n_cliffords) + ] + + truncated_cliffords_2b = [ + [ + quaff.TruncatedCliffordGate.random(len(qubits), rng_2b) + for qubits in qubit_partition + ] + for _ in range(n_cliffords) + ] + + resolvers_1a = [ + quaff.get_truncated_cliffords_resolver(gates) + for gates in truncated_cliffords_1a + ] + resolvers_1b = [ + quaff.get_truncated_cliffords_resolver(gates) + for gates in truncated_cliffords_1b + ] + resolvers_2a = [ + quaff.get_truncated_cliffords_resolver(gates) + for gates in truncated_cliffords_2a + ] + resolvers_2b = [ + quaff.get_truncated_cliffords_resolver(gates) + for gates in truncated_cliffords_2b + ] + + assert resolvers_1a == resolvers_1b + assert resolvers_2a == resolvers_2b + assert resolvers_1a != resolvers_2a + + assert isinstance(resolvers_1a[0]["h_0_0"], np.integer) + + +def test_truncated_cliffords_partitioning(): + qubit_partition = [cirq.LineQubit.range(2), cirq.LineQubit.range(2, 6)] + n_cliffords = 7 + seed = 3 + + truncated_cliffords = list( + _get_truncated_cliffords( + n_cliffords=n_cliffords, qubit_partition=qubit_partition, seed=seed + ) + ) + + assert len(truncated_cliffords) == 7 + for clifford_set in truncated_cliffords: + assert len(clifford_set) == 2 + for part, clifford in zip(qubit_partition, clifford_set): + assert len(part) == clifford._num_qubits diff --git a/recirq/qcqmc/optimize_wf_test.py b/recirq/qcqmc/optimize_wf_test.py index 15b7e2fa..830120ea 100644 --- a/recirq/qcqmc/optimize_wf_test.py +++ b/recirq/qcqmc/optimize_wf_test.py @@ -19,18 +19,14 @@ import pytest from recirq.qcqmc.afqmc_generators import get_pp_plus_gate_generators -from recirq.qcqmc.converters import ( - get_ansatz_qubit_wf, - get_two_body_params_from_qchem_amplitudes, -) +from recirq.qcqmc.converters import (get_ansatz_qubit_wf, + get_two_body_params_from_qchem_amplitudes) from recirq.qcqmc.hamiltonian import HamiltonianData from recirq.qcqmc.layer_spec import LayerSpec -from recirq.qcqmc.optimize_wf import ( - build_pp_plus_trial_wavefunction, - compute_finite_difference_grad, - evaluate_energy_and_gradient, - get_evolved_wf, -) +from recirq.qcqmc.optimize_wf import (build_pp_plus_trial_wavefunction, + compute_finite_difference_grad, + evaluate_energy_and_gradient, + get_evolved_wf) from recirq.qcqmc.trial_wf import PerfectPairingPlusTrialWavefunctionParams @@ -119,6 +115,7 @@ def test_pp_plus_wf_energy_sloppy_1(fixture_8_qubit_ham: HamiltonianData): assert trial_wf.ansatz_energy < -1.947 +@pytest.mark.slow def test_diamond_pp_wf_energy(fixture_12_qubit_ham: HamiltonianData): params = PerfectPairingPlusTrialWavefunctionParams( name="diamind_pp_test_wf_1", diff --git a/recirq/qcqmc/trial_wf.py b/recirq/qcqmc/trial_wf.py index eeea6585..b151386d 100644 --- a/recirq/qcqmc/trial_wf.py +++ b/recirq/qcqmc/trial_wf.py @@ -70,7 +70,7 @@ def _to_tuple(x: Iterable[layer_spec.LayerSpec]) -> Sequence[layer_spec.LayerSpe return tuple(x) -@attrs.frozen(repr=False) +@attrs.frozen(repr=False, eq=False) class PerfectPairingPlusTrialWavefunctionParams(TrialWavefunctionParams): """Class for storing the parameters that specify the trial wavefunction. @@ -112,12 +112,10 @@ class PerfectPairingPlusTrialWavefunctionParams(TrialWavefunctionParams): initial_orbital_rotation: Optional[np.ndarray] = attrs.field( default=None, converter=lambda v: _to_numpy(v) if v is not None else None, - eq=attrs.cmp_using(eq=np.array_equal), ) initial_two_body_qchem_amplitudes: Optional[np.ndarray] = attrs.field( default=None, converter=lambda v: _to_numpy(v) if v is not None else None, - eq=attrs.cmp_using(eq=np.array_equal), ) do_optimization: bool = True use_fast_gradients: bool = False