From dd245775987443d95d630ab47546eb0cfef5cdb8 Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Wed, 11 Dec 2024 21:40:15 -0800 Subject: [PATCH 1/4] Multiple fixes and enhancements to dependabot.yml (#6834) * Multiple fixes and enhancements to dependabot.yml * Changes Python versioning strategy to be `widen`. Per the GitHub docs: "Widen the allowed version requirements to include both the new and old versions, when possible. Typically, this only increases the maximum allowed version requirement." * Fixes the pip/Python case to look for requirements files in all the places where we have them. * Fixes the npm case to look for `package.json` in the right place. * Add / to pip directories searched The directories list for the pip/python case should probably include "/" to be on the safe side. --- .github/dependabot.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cd6f523c049..748abcace19 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -22,6 +22,8 @@ version: 2 updates: - package-ecosystem: "docker" + # The "docker" ecosystem directive makes Dependabot look for a Dockerfile + # in the specified directory. directory: "/" schedule: interval: "weekly" @@ -31,6 +33,8 @@ updates: - "kind/health" - package-ecosystem: "github-actions" + # The "github-actions" code explicitly looks in /.github/workflows if the + # value "/" is given for the directory attribute. Yes, that's confusing. directory: "/" schedule: interval: "weekly" @@ -40,7 +44,9 @@ updates: - "kind/health" - package-ecosystem: "npm" - directory: "/" + # The "npm" ecosystem directive makes Dependabot look for package.json in + # the specified directory. + directory: "/cirq-web/cirq_ts/" schedule: interval: "weekly" labels: @@ -49,9 +55,21 @@ updates: - "kind/health" - package-ecosystem: "pip" - directory: "/" + # Cirq has requirements.txt files in multiple places. N.b. the use of + # attribute "directories" instead of "directory" here. + directories: + - "/" + - "/cirq-aqt" + - "/cirq-core" + - "/cirq-google" + - "/cirq-ionq" + - "/cirq-pasqal" + - "/cirq-rigetti" + - "/cirq-web" + - "/dev_tools/requirements" schedule: interval: "weekly" + versioning-strategy: "widen" labels: - "area/dependencies" - "area/python" From 0c7ee0c1a490652c394f24ed94d69f676e07ee2c Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Thu, 12 Dec 2024 13:26:52 -0800 Subject: [PATCH 2/4] Use strategy "increase-if-necessary" in dependabot.yml (#6839) * Multiple fixes and enhancements to dependabot.yml * Changes Python versioning strategy to be `widen`. Per the GitHub docs: "Widen the allowed version requirements to include both the new and old versions, when possible. Typically, this only increases the maximum allowed version requirement." * Fixes the pip/Python case to look for requirements files in all the places where we have them. * Fixes the npm case to look for `package.json` in the right place. * Add / to pip directories searched The directories list for the pip/python case should probably include "/" to be on the safe side. * Switch strategy to increase-if-necessary Turns out the "widen" strategy is not available for pip. Switch to "increase-if-necessary". --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 748abcace19..a26cfc2607a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -69,7 +69,7 @@ updates: - "/dev_tools/requirements" schedule: interval: "weekly" - versioning-strategy: "widen" + versioning-strategy: "increase-if-necessary" labels: - "area/dependencies" - "area/python" From 4d03aea78233ae0af8129e84a9c412f69e8c286c Mon Sep 17 00:00:00 2001 From: Noureldin Date: Thu, 12 Dec 2024 13:50:58 -0800 Subject: [PATCH 3/4] Add ability to pass tags to XEB and related methods (#6836) --- .../random_quantum_circuit_generation.py | 4 +++- .../random_quantum_circuit_generation_test.py | 17 +++++++++++++++++ cirq-core/cirq/experiments/two_qubit_xeb.py | 11 ++++++++++- .../cirq/experiments/z_phase_calibration.py | 14 +++++++++++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/experiments/random_quantum_circuit_generation.py b/cirq-core/cirq/experiments/random_quantum_circuit_generation.py index 8a5d92058eb..350211a3ad9 100644 --- a/cirq-core/cirq/experiments/random_quantum_circuit_generation.py +++ b/cirq-core/cirq/experiments/random_quantum_circuit_generation.py @@ -250,6 +250,7 @@ def generate_library_of_2q_circuits( q0: 'cirq.Qid' = devices.LineQubit(0), q1: 'cirq.Qid' = devices.LineQubit(1), random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + tags: Sequence[Any] = (), ) -> List['cirq.Circuit']: """Generate a library of two-qubit Circuits. @@ -266,6 +267,7 @@ def generate_library_of_2q_circuits( q0: The first qubit to use when constructing the circuits. q1: The second qubit to use when constructing the circuits random_state: A random state or seed used to deterministically sample the random circuits. + tags: Tags to add to the two qubit operations. """ rs = value.parse_random_state(random_state) exponents = np.linspace(0, 7 / 4, 8) @@ -278,7 +280,7 @@ def generate_library_of_2q_circuits( q0, q1, depth=max_cycle_depth, - two_qubit_op_factory=lambda a, b, _: two_qubit_gate(a, b), + two_qubit_op_factory=lambda a, b, _: two_qubit_gate(a, b).with_tags(*tags), single_qubit_gates=single_qubit_gates, seed=rs, ) diff --git a/cirq-core/cirq/experiments/random_quantum_circuit_generation_test.py b/cirq-core/cirq/experiments/random_quantum_circuit_generation_test.py index 115bf737dc2..c8397415d04 100644 --- a/cirq-core/cirq/experiments/random_quantum_circuit_generation_test.py +++ b/cirq-core/cirq/experiments/random_quantum_circuit_generation_test.py @@ -457,3 +457,20 @@ def add_pair(neighbor: 'cirq.GridQubit'): add_pair(cirq.GridQubit(qubit.row + 1, qubit.col)) return pairs + + +def test_generate_library_of_2q_circuits_with_tags(): + circuits = generate_library_of_2q_circuits( + n_library_circuits=5, + two_qubit_gate=cirq.FSimGate(3, 4), + max_cycle_depth=13, + random_state=9, + tags=('test_tag',), + ) + assert len(circuits) == 5 + for circuit in circuits: + for op in circuit.all_operations(): + if cirq.num_qubits(op) == 1: + continue + assert op.tags == ('test_tag',) + assert op.gate == cirq.FSimGate(3, 4) diff --git a/cirq-core/cirq/experiments/two_qubit_xeb.py b/cirq-core/cirq/experiments/two_qubit_xeb.py index 12162d0e883..6fe20529dd6 100644 --- a/cirq-core/cirq/experiments/two_qubit_xeb.py +++ b/cirq-core/cirq/experiments/two_qubit_xeb.py @@ -13,7 +13,7 @@ # limitations under the License. """Provides functions for running and analyzing two-qubit XEB experiments.""" -from typing import Sequence, TYPE_CHECKING, Optional, Tuple, Dict, cast, Mapping +from typing import Sequence, TYPE_CHECKING, Optional, Tuple, Dict, cast, Mapping, Any from dataclasses import dataclass from types import MappingProxyType @@ -402,6 +402,7 @@ def parallel_xeb_workflow( pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None, pool: Optional['multiprocessing.pool.Pool'] = None, batch_size: int = 9, + tags: Sequence[Any] = (), **plot_kwargs, ) -> Tuple[pd.DataFrame, Sequence['cirq.Circuit'], pd.DataFrame]: """A utility method that runs the full XEB workflow. @@ -422,6 +423,7 @@ def parallel_xeb_workflow( batch_size: We call `run_batch` on the sampler, which can speed up execution in certain environments. The number of (circuit, cycle_depth) tasks to be run in each batch is given by this number. + tags: Tags to add to two qubit operations. **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'. Returns: @@ -450,6 +452,7 @@ def parallel_xeb_workflow( two_qubit_gate=entangling_gate, random_state=rs, max_cycle_depth=max(cycle_depths), + tags=tags, ) combs_by_layer = rqcg.get_random_combinations_for_device( @@ -488,6 +491,7 @@ def parallel_two_qubit_xeb( ax: Optional[plt.Axes] = None, pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None, batch_size: int = 9, + tags: Sequence[Any] = (), **plot_kwargs, ) -> TwoQubitXEBResult: """A convenience method that runs the full XEB workflow. @@ -507,6 +511,7 @@ def parallel_two_qubit_xeb( batch_size: We call `run_batch` on the sampler, which can speed up execution in certain environments. The number of (circuit, cycle_depth) tasks to be run in each batch is given by this number. + tags: Tags to add to two qubit operations. **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'. Returns: A TwoQubitXEBResult object representing the results of the experiment. @@ -525,6 +530,7 @@ def parallel_two_qubit_xeb( random_state=random_state, ax=ax, batch_size=batch_size, + tags=tags, **plot_kwargs, ) return TwoQubitXEBResult(fit_exponential_decays(fids)) @@ -544,6 +550,7 @@ def run_rb_and_xeb( random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None, batch_size: int = 9, + tags: Sequence[Any] = (), ) -> InferredXEBResult: """A convenience method that runs both RB and XEB workflows. @@ -561,6 +568,7 @@ def run_rb_and_xeb( batch_size: We call `run_batch` on the sampler, which can speed up execution in certain environments. The number of (circuit, cycle_depth) tasks to be run in each batch is given by this number. + tags: Tags to add to two qubit operations. Returns: An InferredXEBResult object representing the results of the experiment. @@ -590,6 +598,7 @@ def run_rb_and_xeb( n_combinations=xeb_combinations, random_state=random_state, batch_size=batch_size, + tags=tags, ) return InferredXEBResult(rb, xeb) diff --git a/cirq-core/cirq/experiments/z_phase_calibration.py b/cirq-core/cirq/experiments/z_phase_calibration.py index 363810fbd13..8e58cab7569 100644 --- a/cirq-core/cirq/experiments/z_phase_calibration.py +++ b/cirq-core/cirq/experiments/z_phase_calibration.py @@ -13,7 +13,7 @@ # limitations under the License. """Provides a method to do z-phase calibration for excitation-preserving gates.""" -from typing import Union, Optional, Sequence, Tuple, Dict, TYPE_CHECKING +from typing import Union, Optional, Sequence, Tuple, Dict, TYPE_CHECKING, Any import multiprocessing import multiprocessing.pool @@ -41,6 +41,8 @@ def z_phase_calibration_workflow( random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, atol: float = 1e-3, num_workers_or_pool: Union[int, 'multiprocessing.pool.Pool'] = -1, + pairs: Optional[Sequence[Tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None, + tags: Sequence[Any] = (), ) -> Tuple[xeb_fitting.XEBCharacterizationResult, 'pd.DataFrame']: """Perform z-phase calibration for excitation-preserving gates. @@ -77,6 +79,8 @@ def z_phase_calibration_workflow( A zero value means no multiprocessing. A positive integer value will create a pool with the given number of workers. A negative value will create pool with maximum number of workers. + pairs: Pairs to use. If not specified, use all pairs between adjacent qubits. + tags: Tags to add to two qubit operations. Returns: - An `XEBCharacterizationResult` object that contains the calibration result. - A `pd.DataFrame` comparing the before and after fidelities. @@ -100,6 +104,8 @@ def z_phase_calibration_workflow( n_combinations=n_combinations, random_state=random_state, pool=pool, + tags=tags, + pairs=pairs, ) if options is None: @@ -148,6 +154,8 @@ def calibrate_z_phases( random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, atol: float = 1e-3, num_workers_or_pool: Union[int, 'multiprocessing.pool.Pool'] = -1, + pairs: Optional[Sequence[Tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None, + tags: Sequence[Any] = (), ) -> Dict[Tuple['cirq.Qid', 'cirq.Qid'], 'cirq.PhasedFSimGate']: """Perform z-phase calibration for excitation-preserving gates. @@ -184,6 +192,8 @@ def calibrate_z_phases( A zero value means no multiprocessing. A positive integer value will create a pool with the given number of workers. A negative value will create pool with maximum number of workers. + pairs: Pairs to use. If not specified, use all pairs between adjacent qubits. + tags: Tags to add to two qubit operations. Returns: - A dictionary mapping qubit pairs to the calibrated PhasedFSimGates. @@ -210,6 +220,8 @@ def calibrate_z_phases( random_state=random_state, atol=atol, num_workers_or_pool=num_workers_or_pool, + tags=tags, + pairs=pairs, ) gates = {} From ea605d48db5f72870e7e9a42ee70df3d967fe94a Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Fri, 13 Dec 2024 13:41:10 -0800 Subject: [PATCH 4/4] Disable local Google Cloud credentials in tests (#6851) Prevent tested notebooks from connecting to cloud services with local user credentials. Tell gcloud to use empty configuration directory instead of user configuration within pytest session. This makes the test of docs/tutorials/google/start.ipynb notebook use virtual hardware engine unconditionally. --- dev_tools/conftest.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dev_tools/conftest.py b/dev_tools/conftest.py index 2e7bb5fc556..708c77a3347 100644 --- a/dev_tools/conftest.py +++ b/dev_tools/conftest.py @@ -11,6 +11,7 @@ # 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 os import shutil import sys @@ -18,6 +19,7 @@ import uuid from pathlib import Path from typing import Tuple +from unittest import mock import pytest from filelock import FileLock @@ -26,6 +28,14 @@ from dev_tools.env_tools import create_virtual_env +@pytest.fixture(scope="session", autouse=True) +def disable_local_gcloud_credentials(tmp_path_factory): + # Ensure tests cannot authenticate to production servers with user credentials + empty_dir = tmp_path_factory.mktemp("empty_gcloud_config", numbered=False) + with mock.patch.dict(os.environ, {"CLOUDSDK_CONFIG": str(empty_dir)}): + yield + + @pytest.fixture(scope="session") def cloned_env(testrun_uid, worker_id): """Fixture to allow tests to run in a clean virtual env.