diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79519fcb..5f92b32d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,8 @@ first create a virtual Python environment. You can use either Python's built-in [`venv`](https://docs.python.org/3/library/venv.html) module or another tool that you are comfortable with. -Then, in that virtual environment, install the ReCirq dependencies using `pip`: +Then, in that virtual environment, install the core ReCirq dependencies using +`pip`: ```shell pip install -r requirements.txt @@ -90,27 +91,33 @@ need to install its extra dependencies like this: pip install -r recirq/optimize/extra-requirements.txt ``` -Finally, if you are going to edit any of the Jupyter notebooks, install the -additional requirements needed to run the notebook format checks: +Once the environment is set up, you can do your work and `git commit` your +changes to your branch as needed. + +#### Running tests + +To test your code when working on the module for a given experiment, run +`pytest` with the path to the module. Continuing with the `recirq/optimize` +module as an example, you would run the following command: ```shell -pip install -r dev_tools/requirements/deps/tensorflow-docs.txt +pytest recirq/optimize ``` -Once the environment is set up, you can do your work and `git commit` your -changes to your branch as needed. +#### Writing and editing notebooks -To test notebooks for proper formatting and other issues, run the following -command: +If you are going to edit any of the Jupyter notebooks, install the +additional requirements needed to run the notebook format checks: ```shell -dev_tools/nbformat +pip install -r dev_tools/requirements/deps/tensorflow-docs.txt ``` -To test your code, run +After that, you can test notebooks for proper formatting and other issues with +this command: ```shell -pytest recirq +dev_tools/nbformat ``` ### Pull requests and code reviews diff --git a/conftest.py b/conftest.py index 46bcc2db..ecce4d44 100644 --- a/conftest.py +++ b/conftest.py @@ -11,184 +11,9 @@ # 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 pathlib -from typing import Dict, Tuple -import numpy as np import pytest -from recirq.qcqmc import analysis, blueprint, data, experiment, qubit_maps -from recirq.qcqmc.hamiltonian import ( - HamiltonianData, - HamiltonianFileParams, -) -from recirq.qcqmc.trial_wf import ( - PerfectPairingPlusTrialWavefunctionParams, - TrialWavefunctionData, -) - - -@pytest.fixture(scope="package") -def package_tmp_path(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path: - return tmp_path_factory.mktemp("data", numbered=True) - - -@pytest.fixture(scope="package") -def fixture_4_qubit_ham(package_tmp_path) -> HamiltonianData: - params = HamiltonianFileParams( - name="test hamiltonian 4 qubits", - integral_key="fh_sto3g", - n_orb=2, - n_elec=2, - path_prefix=str(package_tmp_path), - ) - - hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) - - return hamiltonian_data - - -@pytest.fixture(scope="package") -def fixture_8_qubit_ham(package_tmp_path) -> HamiltonianData: - params = HamiltonianFileParams( - name="test hamiltonian 8 qubits", - integral_key="h4_sto3g", - n_orb=4, - n_elec=4, - path_prefix=str(package_tmp_path), - ) - - hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) - - return hamiltonian_data - - -@pytest.fixture(scope="package") -def fixture_12_qubit_ham(package_tmp_path) -> HamiltonianData: - params = HamiltonianFileParams( - name="test hamiltonian 12 qubits", - integral_key="diamond_dzvp/cas66", - n_orb=6, - n_elec=6, - do_eri_restore=True, - path_prefix=str(package_tmp_path), - ) - - hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) - - return hamiltonian_data - - -@pytest.fixture(scope="package") -def fixture_4_qubit_ham_and_trial_wf( - fixture_4_qubit_ham: HamiltonianData, -) -> Tuple[HamiltonianData, TrialWavefunctionData]: - params = PerfectPairingPlusTrialWavefunctionParams( - name="pp_test_wf_1", - hamiltonian_params=fixture_4_qubit_ham.params, - heuristic_layers=tuple(), - do_pp=True, - restricted=True, - path_prefix=fixture_4_qubit_ham.params.path_prefix, - ) - - trial_wf = TrialWavefunctionData.build_pp_plus_trial_from_dependencies( - params, dependencies={fixture_4_qubit_ham.params: fixture_4_qubit_ham} - ) - - return fixture_4_qubit_ham, trial_wf - - -@pytest.fixture(scope="package") -def fixture_8_qubit_ham_and_trial_wf( - fixture_8_qubit_ham: HamiltonianData, -) -> Tuple[HamiltonianData, TrialWavefunctionData]: - params = PerfectPairingPlusTrialWavefunctionParams( - name="pp_test_wf_qchem", - hamiltonian_params=fixture_8_qubit_ham.params, - heuristic_layers=tuple(), - initial_orbital_rotation=None, - initial_two_body_qchem_amplitudes=np.asarray([0.3, 0.4]), - do_optimization=False, - path_prefix=fixture_8_qubit_ham.params.path_prefix, - ) - - trial_wf = TrialWavefunctionData.build_pp_plus_trial_from_dependencies( - params, dependencies={fixture_8_qubit_ham.params: fixture_8_qubit_ham} - ) - - return fixture_8_qubit_ham, trial_wf - - -@pytest.fixture(scope="package") -def fixture_4_qubit_ham_trial_wf_and_blueprint( - fixture_4_qubit_ham_and_trial_wf, -) -> Tuple[HamiltonianData, TrialWavefunctionData, blueprint.BlueprintData]: - ham_data, trial_wf_data = fixture_4_qubit_ham_and_trial_wf - trial_wf_params = trial_wf_data.params - - blueprint_params = blueprint.BlueprintParamsTrialWf( - name="blueprint_test", - trial_wf_params=trial_wf_params, - n_cliffords=17, - qubit_partition=( - tuple(qubit_maps.get_qubits_a_b_reversed(n_orb=trial_wf_params.n_orb)), - ), - seed=1, - path_prefix=ham_data.params.path_prefix, - ) - - bp = blueprint.BlueprintData.build_blueprint_from_dependencies( - blueprint_params, dependencies={trial_wf_params: trial_wf_data} - ) - - return ham_data, trial_wf_data, bp - - -@pytest.fixture(scope="package") -def fixture_4_qubit_ham_trial_wf_and_overlap_analysis( - fixture_4_qubit_ham_trial_wf_and_blueprint, -) -> Tuple[HamiltonianData, TrialWavefunctionData, analysis.OverlapAnalysisData]: - """Construct fixtures for the hamiltonian, trial wavefunction and overlap analysis. - - Returns: - ham_data: The hamiltonian for the 4 qubit test system. - trial_wf_data: The trial wavefunction data for the 4 qubit system. - ovlp_analysis: The overlap analysis data used to reconstruct the - wavefunction via shadow tomography. - """ - ham_data, trial_wf_data, bp_data = fixture_4_qubit_ham_trial_wf_and_blueprint - simulated_experiment_params = experiment.SimulatedExperimentParams( - name="test_1", - blueprint_params=bp_data.params, - noise_model_name="None", - noise_model_params=(0,), - n_samples_per_clifford=10, - seed=1, - path_prefix=ham_data.params.path_prefix, - ) - exp = experiment.ExperimentData.build_experiment_from_dependencies( - params=simulated_experiment_params, dependencies={bp_data.params: bp_data} - ) - - analysis_params = analysis.OverlapAnalysisParams( - "TEST_analysis", - experiment_params=exp.params, - k_to_calculate=(1,), - path_prefix=ham_data.params.path_prefix, - ) - all_dependencies: Dict[data.Params, data.Data] = { - ham_data.params: ham_data, - trial_wf_data.params: trial_wf_data, - bp_data.params: bp_data, - simulated_experiment_params: exp, - } - ovlp_analysis = analysis.OverlapAnalysisData.build_analysis_from_dependencies( - analysis_params, dependencies=all_dependencies - ) - - return ham_data, trial_wf_data, ovlp_analysis - def pytest_addoption(parser): parser.addoption("--skipslow", action="store_true", help="skips slow tests") diff --git a/recirq/qcqmc/conftest.py b/recirq/qcqmc/conftest.py new file mode 100644 index 00000000..58b105b2 --- /dev/null +++ b/recirq/qcqmc/conftest.py @@ -0,0 +1,191 @@ +# 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 pathlib +from typing import Dict, Tuple + +import numpy as np +import pytest + +from recirq.qcqmc import analysis, blueprint, data, experiment, qubit_maps +from recirq.qcqmc.hamiltonian import ( + HamiltonianData, + HamiltonianFileParams, +) +from recirq.qcqmc.trial_wf import ( + PerfectPairingPlusTrialWavefunctionParams, + TrialWavefunctionData, +) + + +@pytest.fixture(scope="package") +def package_tmp_path(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path: + return tmp_path_factory.mktemp("data", numbered=True) + + +@pytest.fixture(scope="package") +def fixture_4_qubit_ham(package_tmp_path) -> HamiltonianData: + params = HamiltonianFileParams( + name="test hamiltonian 4 qubits", + integral_key="fh_sto3g", + n_orb=2, + n_elec=2, + path_prefix=str(package_tmp_path), + ) + + hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) + + return hamiltonian_data + + +@pytest.fixture(scope="package") +def fixture_8_qubit_ham(package_tmp_path) -> HamiltonianData: + params = HamiltonianFileParams( + name="test hamiltonian 8 qubits", + integral_key="h4_sto3g", + n_orb=4, + n_elec=4, + path_prefix=str(package_tmp_path), + ) + + hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) + + return hamiltonian_data + + +@pytest.fixture(scope="package") +def fixture_12_qubit_ham(package_tmp_path) -> HamiltonianData: + params = HamiltonianFileParams( + name="test hamiltonian 12 qubits", + integral_key="diamond_dzvp/cas66", + n_orb=6, + n_elec=6, + do_eri_restore=True, + path_prefix=str(package_tmp_path), + ) + + hamiltonian_data = HamiltonianData.build_hamiltonian_from_file(params) + + return hamiltonian_data + + +@pytest.fixture(scope="package") +def fixture_4_qubit_ham_and_trial_wf( + fixture_4_qubit_ham: HamiltonianData, +) -> Tuple[HamiltonianData, TrialWavefunctionData]: + params = PerfectPairingPlusTrialWavefunctionParams( + name="pp_test_wf_1", + hamiltonian_params=fixture_4_qubit_ham.params, + heuristic_layers=tuple(), + do_pp=True, + restricted=True, + path_prefix=fixture_4_qubit_ham.params.path_prefix, + ) + + trial_wf = TrialWavefunctionData.build_pp_plus_trial_from_dependencies( + params, dependencies={fixture_4_qubit_ham.params: fixture_4_qubit_ham} + ) + + return fixture_4_qubit_ham, trial_wf + + +@pytest.fixture(scope="package") +def fixture_8_qubit_ham_and_trial_wf( + fixture_8_qubit_ham: HamiltonianData, +) -> Tuple[HamiltonianData, TrialWavefunctionData]: + params = PerfectPairingPlusTrialWavefunctionParams( + name="pp_test_wf_qchem", + hamiltonian_params=fixture_8_qubit_ham.params, + heuristic_layers=tuple(), + initial_orbital_rotation=None, + initial_two_body_qchem_amplitudes=np.asarray([0.3, 0.4]), + do_optimization=False, + path_prefix=fixture_8_qubit_ham.params.path_prefix, + ) + + trial_wf = TrialWavefunctionData.build_pp_plus_trial_from_dependencies( + params, dependencies={fixture_8_qubit_ham.params: fixture_8_qubit_ham} + ) + + return fixture_8_qubit_ham, trial_wf + + +@pytest.fixture(scope="package") +def fixture_4_qubit_ham_trial_wf_and_blueprint( + fixture_4_qubit_ham_and_trial_wf, +) -> Tuple[HamiltonianData, TrialWavefunctionData, blueprint.BlueprintData]: + ham_data, trial_wf_data = fixture_4_qubit_ham_and_trial_wf + trial_wf_params = trial_wf_data.params + + blueprint_params = blueprint.BlueprintParamsTrialWf( + name="blueprint_test", + trial_wf_params=trial_wf_params, + n_cliffords=17, + qubit_partition=( + tuple(qubit_maps.get_qubits_a_b_reversed(n_orb=trial_wf_params.n_orb)), + ), + seed=1, + path_prefix=ham_data.params.path_prefix, + ) + + bp = blueprint.BlueprintData.build_blueprint_from_dependencies( + blueprint_params, dependencies={trial_wf_params: trial_wf_data} + ) + + return ham_data, trial_wf_data, bp + + +@pytest.fixture(scope="package") +def fixture_4_qubit_ham_trial_wf_and_overlap_analysis( + fixture_4_qubit_ham_trial_wf_and_blueprint, +) -> Tuple[HamiltonianData, TrialWavefunctionData, analysis.OverlapAnalysisData]: + """Construct fixtures for the hamiltonian, trial wavefunction and overlap analysis. + + Returns: + ham_data: The hamiltonian for the 4 qubit test system. + trial_wf_data: The trial wavefunction data for the 4 qubit system. + ovlp_analysis: The overlap analysis data used to reconstruct the + wavefunction via shadow tomography. + """ + ham_data, trial_wf_data, bp_data = fixture_4_qubit_ham_trial_wf_and_blueprint + simulated_experiment_params = experiment.SimulatedExperimentParams( + name="test_1", + blueprint_params=bp_data.params, + noise_model_name="None", + noise_model_params=(0,), + n_samples_per_clifford=10, + seed=1, + path_prefix=ham_data.params.path_prefix, + ) + exp = experiment.ExperimentData.build_experiment_from_dependencies( + params=simulated_experiment_params, dependencies={bp_data.params: bp_data} + ) + + analysis_params = analysis.OverlapAnalysisParams( + "TEST_analysis", + experiment_params=exp.params, + k_to_calculate=(1,), + path_prefix=ham_data.params.path_prefix, + ) + all_dependencies: Dict[data.Params, data.Data] = { + ham_data.params: ham_data, + trial_wf_data.params: trial_wf_data, + bp_data.params: bp_data, + simulated_experiment_params: exp, + } + ovlp_analysis = analysis.OverlapAnalysisData.build_analysis_from_dependencies( + analysis_params, dependencies=all_dependencies + ) + + return ham_data, trial_wf_data, ovlp_analysis