From 6186a3843d6c3a8fcc99dcce53bd4af0ebc059a8 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Mon, 22 Sep 2025 18:04:26 -0700 Subject: [PATCH 1/4] Don't refresh the job as soon as we receive the result. - Currently, each streaming result refreshes the result. - Forgoing this can reduce batch result times by 3x. --- cirq-google/cirq_google/engine/engine_job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/engine/engine_job.py b/cirq-google/cirq_google/engine/engine_job.py index 5ab0f249ff7..8d756f61fde 100644 --- a/cirq-google/cirq_google/engine/engine_job.py +++ b/cirq-google/cirq_google/engine/engine_job.py @@ -340,7 +340,7 @@ def _get_job_results_v1(self, result: v1.program_pb2.Result) -> Sequence[EngineR def _get_job_results_v2(self, result: v2.result_pb2.Result) -> Sequence[EngineResult]: sweep_results = v2.results_from_proto(result) job_id = self.id() - job_finished = self.update_time() + job_finished = datetime.datetime.now() # Flatten to single list to match to sampler api. return [ From 5bd499ea8e8825d750e8b7476782ff8ada033630 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Tue, 23 Sep 2025 10:22:13 -0700 Subject: [PATCH 2/4] Just remove job_finished_time. --- cirq-google/cirq_google/engine/engine_job.py | 3 +-- cirq-google/cirq_google/engine/engine_processor_test.py | 2 -- cirq-google/cirq_google/engine/engine_program_test.py | 2 +- cirq-google/cirq_google/engine/engine_result.py | 6 ++++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cirq-google/cirq_google/engine/engine_job.py b/cirq-google/cirq_google/engine/engine_job.py index 8d756f61fde..52d00f9845d 100644 --- a/cirq-google/cirq_google/engine/engine_job.py +++ b/cirq-google/cirq_google/engine/engine_job.py @@ -340,11 +340,10 @@ def _get_job_results_v1(self, result: v1.program_pb2.Result) -> Sequence[EngineR def _get_job_results_v2(self, result: v2.result_pb2.Result) -> Sequence[EngineResult]: sweep_results = v2.results_from_proto(result) job_id = self.id() - job_finished = datetime.datetime.now() # Flatten to single list to match to sampler api. return [ - EngineResult.from_result(result, job_id=job_id, job_finished_time=job_finished) + EngineResult.from_result(result, job_id=job_id) for sweep_result in sweep_results for result in sweep_result ] diff --git a/cirq-google/cirq_google/engine/engine_processor_test.py b/cirq-google/cirq_google/engine/engine_processor_test.py index d359271e5da..5847ffa0647 100644 --- a/cirq-google/cirq_google/engine/engine_processor_test.py +++ b/cirq-google/cirq_google/engine/engine_processor_test.py @@ -901,7 +901,6 @@ def test_run_sweep_params_with_unary_rpcs(client): assert results[i].measurements == {'q': np.array([[0]], dtype='uint8')} for result in results: assert result.job_id == job.id() - assert result.job_finished_time is not None assert results == cirq.read_json(json_text=cirq.to_json(results)) client().create_program_async.assert_called_once() @@ -943,7 +942,6 @@ def test_run_sweep_params_with_stream_rpcs(client): assert results[i].measurements == {'q': np.array([[0]], dtype='uint8')} for result in results: assert result.job_id == job.id() - assert result.job_finished_time is not None assert results == cirq.read_json(json_text=cirq.to_json(results)) client().run_job_over_stream.assert_called_once() diff --git a/cirq-google/cirq_google/engine/engine_program_test.py b/cirq-google/cirq_google/engine/engine_program_test.py index dde915eb643..b111a269a0a 100644 --- a/cirq-google/cirq_google/engine/engine_program_test.py +++ b/cirq-google/cirq_google/engine/engine_program_test.py @@ -152,7 +152,7 @@ def test_run_delegation(create_job_async, get_results_async): params=cirq.ParamResolver({'a': 1.0}), measurements={'q': np.array([[False], [True], [True], [False]], dtype=bool)}, job_id='steve', - job_finished_time=dt, + job_finished_time=None, ) diff --git a/cirq-google/cirq_google/engine/engine_result.py b/cirq-google/cirq_google/engine/engine_result.py index 4c71f77aebb..58080e1c4a4 100644 --- a/cirq-google/cirq_google/engine/engine_result.py +++ b/cirq-google/cirq_google/engine/engine_result.py @@ -39,7 +39,7 @@ def __init__( self, *, # Forces keyword args. job_id: str, - job_finished_time: datetime.datetime, + job_finished_time: datetime.datetime | None = None, params: study.ParamResolver | None = None, measurements: Mapping[str, np.ndarray] | None = None, records: Mapping[str, np.ndarray] | None = None, @@ -60,7 +60,9 @@ def __init__( self.job_finished_time = job_finished_time @classmethod - def from_result(cls, result: cirq.Result, *, job_id: str, job_finished_time: datetime.datetime): + def from_result( + cls, result: cirq.Result, *, job_id: str, job_finished_time: datetime.datetime | None = None + ): if isinstance(result, study.ResultDict): # optimize by using private methods return cls( From 62c7361d7573b3b18cf7a1b2618eeeab48be1a86 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Tue, 23 Sep 2025 10:22:13 -0700 Subject: [PATCH 3/4] Just remove job_finished_time. --- cirq-google/cirq_google/engine/engine_job.py | 5 +--- .../engine/engine_processor_test.py | 2 -- .../cirq_google/engine/engine_program_test.py | 1 - .../cirq_google/engine/engine_result.py | 24 ++++--------------- .../cirq_google/engine/engine_result_test.py | 11 ++------- .../cirq_google/engine/simulated_local_job.py | 13 ++-------- .../cirq.google.EngineResult.json | 8 ++----- .../cirq.google.EngineResult.repr | 2 +- 8 files changed, 13 insertions(+), 53 deletions(-) diff --git a/cirq-google/cirq_google/engine/engine_job.py b/cirq-google/cirq_google/engine/engine_job.py index 8d756f61fde..e169ff994d2 100644 --- a/cirq-google/cirq_google/engine/engine_job.py +++ b/cirq-google/cirq_google/engine/engine_job.py @@ -317,7 +317,6 @@ async def _await_result_async(self) -> quantum.QuantumResult: def _get_job_results_v1(self, result: v1.program_pb2.Result) -> Sequence[EngineResult]: job_id = self.id() - job_finished = self.update_time() trial_results = [] for sweep_result in result.sweep_results: @@ -332,7 +331,6 @@ def _get_job_results_v1(self, result: v1.program_pb2.Result) -> Sequence[EngineR params=cirq.ParamResolver(result.params.assignments), measurements=measurements, job_id=job_id, - job_finished_time=job_finished, ) ) return trial_results @@ -340,11 +338,10 @@ def _get_job_results_v1(self, result: v1.program_pb2.Result) -> Sequence[EngineR def _get_job_results_v2(self, result: v2.result_pb2.Result) -> Sequence[EngineResult]: sweep_results = v2.results_from_proto(result) job_id = self.id() - job_finished = datetime.datetime.now() # Flatten to single list to match to sampler api. return [ - EngineResult.from_result(result, job_id=job_id, job_finished_time=job_finished) + EngineResult.from_result(result, job_id=job_id) for sweep_result in sweep_results for result in sweep_result ] diff --git a/cirq-google/cirq_google/engine/engine_processor_test.py b/cirq-google/cirq_google/engine/engine_processor_test.py index d359271e5da..5847ffa0647 100644 --- a/cirq-google/cirq_google/engine/engine_processor_test.py +++ b/cirq-google/cirq_google/engine/engine_processor_test.py @@ -901,7 +901,6 @@ def test_run_sweep_params_with_unary_rpcs(client): assert results[i].measurements == {'q': np.array([[0]], dtype='uint8')} for result in results: assert result.job_id == job.id() - assert result.job_finished_time is not None assert results == cirq.read_json(json_text=cirq.to_json(results)) client().create_program_async.assert_called_once() @@ -943,7 +942,6 @@ def test_run_sweep_params_with_stream_rpcs(client): assert results[i].measurements == {'q': np.array([[0]], dtype='uint8')} for result in results: assert result.job_id == job.id() - assert result.job_finished_time is not None assert results == cirq.read_json(json_text=cirq.to_json(results)) client().run_job_over_stream.assert_called_once() diff --git a/cirq-google/cirq_google/engine/engine_program_test.py b/cirq-google/cirq_google/engine/engine_program_test.py index dde915eb643..f59f2906351 100644 --- a/cirq-google/cirq_google/engine/engine_program_test.py +++ b/cirq-google/cirq_google/engine/engine_program_test.py @@ -152,7 +152,6 @@ def test_run_delegation(create_job_async, get_results_async): params=cirq.ParamResolver({'a': 1.0}), measurements={'q': np.array([[False], [True], [True], [False]], dtype=bool)}, job_id='steve', - job_finished_time=dt, ) diff --git a/cirq-google/cirq_google/engine/engine_result.py b/cirq-google/cirq_google/engine/engine_result.py index 4c71f77aebb..f4c9c72d5d8 100644 --- a/cirq-google/cirq_google/engine/engine_result.py +++ b/cirq-google/cirq_google/engine/engine_result.py @@ -32,14 +32,12 @@ class EngineResult(study.ResultDict): Additional Attributes: job_id: A string job identifier. - job_finished_time: A timestamp for when the job finished. """ def __init__( self, *, # Forces keyword args. job_id: str, - job_finished_time: datetime.datetime, params: study.ParamResolver | None = None, measurements: Mapping[str, np.ndarray] | None = None, records: Mapping[str, np.ndarray] | None = None, @@ -48,7 +46,6 @@ def __init__( Args: job_id: A string job identifier. - job_finished_time: A timestamp for when the job finished; will be converted to UTC. params: A ParamResolver of settings used for this result. measurements: A dictionary from measurement gate key to measurement results. See `cirq.ResultDict`. @@ -57,10 +54,9 @@ def __init__( """ super().__init__(params=params, measurements=measurements, records=records) self.job_id = job_id - self.job_finished_time = job_finished_time @classmethod - def from_result(cls, result: cirq.Result, *, job_id: str, job_finished_time: datetime.datetime): + def from_result(cls, result: cirq.Result, *, job_id: str): if isinstance(result, study.ResultDict): # optimize by using private methods return cls( @@ -68,7 +64,6 @@ def from_result(cls, result: cirq.Result, *, job_id: str, job_finished_time: dat measurements=result._measurements, records=result._records, job_id=job_id, - job_finished_time=job_finished_time, ) else: return cls( @@ -76,25 +71,19 @@ def from_result(cls, result: cirq.Result, *, job_id: str, job_finished_time: dat measurements=result.measurements, records=result.records, job_id=job_id, - job_finished_time=job_finished_time, ) def __eq__(self, other): if not isinstance(other, EngineResult): return False - return ( - super().__eq__(other) - and self.job_id == other.job_id - and self.job_finished_time == other.job_finished_time - ) + return super().__eq__(other) and self.job_id == other.job_id def __repr__(self) -> str: return ( f'cirq_google.EngineResult(params={self.params!r}, ' f'records={self._record_dict_repr()}, ' - f'job_id={self.job_id!r}, ' - f'job_finished_time={self.job_finished_time!r})' + f'job_id={self.job_id!r})' ) @classmethod @@ -104,11 +93,8 @@ def _json_namespace_(cls) -> str: def _json_dict_(self) -> dict[str, Any]: d = super()._json_dict_() d['job_id'] = self.job_id - d['job_finished_time'] = self.job_finished_time return d @classmethod - def _from_json_dict_(cls, params, records, job_id, job_finished_time, **kwargs): - return cls._from_packed_records( - params=params, records=records, job_id=job_id, job_finished_time=job_finished_time - ) + def _from_json_dict_(cls, params, records, job_id, **kwargs): + return cls._from_packed_records(params=params, records=records, job_id=job_id) diff --git a/cirq-google/cirq_google/engine/engine_result_test.py b/cirq-google/cirq_google/engine/engine_result_test.py index fcae39885ed..0a6d7665035 100644 --- a/cirq-google/cirq_google/engine/engine_result_test.py +++ b/cirq-google/cirq_google/engine/engine_result_test.py @@ -31,13 +31,11 @@ def test_engine_result(): res = cg.EngineResult( job_id='my_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) assert res.job_id == 'my_job_id' - assert res.job_finished_time <= datetime.datetime.now(tz=datetime.timezone.utc) assert res.measurements['a'].shape == (2, 2) cirq.testing.assert_equivalent_repr(res, global_vals={'cirq_google': cg}) @@ -46,7 +44,6 @@ def test_engine_result(): def test_engine_result_from_result_dict(): res = cg.EngineResult( job_id='my_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) @@ -57,19 +54,17 @@ def test_engine_result_from_result_dict(): ) assert res2 != res assert res != res2 - assert res == cg.EngineResult.from_result(res2, job_id='my_job_id', job_finished_time=_DT) + assert res == cg.EngineResult.from_result(res2, job_id='my_job_id') def test_engine_result_eq(): res1 = cg.EngineResult( job_id='my_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) res2 = cg.EngineResult( job_id='my_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) @@ -77,7 +72,6 @@ def test_engine_result_eq(): res3 = cg.EngineResult( job_id='my_other_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) @@ -105,10 +99,9 @@ def data(self) -> pd.DataFrame: # pragma: no cover def test_engine_result_from_result(): res = cg.EngineResult( job_id='my_job_id', - job_finished_time=_DT, params=None, measurements={'a': np.array([[0, 0], [1, 1]]), 'b': np.array([[0, 0, 0], [1, 1, 1]])}, ) res2 = MyResult() - assert res == cg.EngineResult.from_result(res2, job_id='my_job_id', job_finished_time=_DT) + assert res == cg.EngineResult.from_result(res2, job_id='my_job_id') diff --git a/cirq-google/cirq_google/engine/simulated_local_job.py b/cirq-google/cirq_google/engine/simulated_local_job.py index cc332b856ff..4580ae825d3 100644 --- a/cirq-google/cirq_google/engine/simulated_local_job.py +++ b/cirq-google/cirq_google/engine/simulated_local_job.py @@ -35,21 +35,12 @@ def _flatten_results(batch_results: Sequence[Sequence[EngineResult]]) -> list[En def _to_engine_results( - batch_results: Sequence[Sequence[cirq.Result]], - *, - job_id: str, - job_finished_time: datetime.datetime | None = None, + batch_results: Sequence[Sequence[cirq.Result]], *, job_id: str ) -> list[list[EngineResult]]: """Convert cirq.Result from simulators into (simulated) EngineResults.""" - if job_finished_time is None: - job_finished_time = datetime.datetime.now(tz=datetime.timezone.utc) - return [ - [ - EngineResult.from_result(result, job_id=job_id, job_finished_time=job_finished_time) - for result in batch - ] + [EngineResult.from_result(result, job_id=job_id) for result in batch] for batch in batch_results ] diff --git a/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.json b/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.json index 8b079d15c82..b933ed5b908 100644 --- a/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.json +++ b/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.json @@ -24,9 +24,5 @@ ] } }, - "job_id": "my_job_id", - "job_finished_time": { - "cirq_type": "datetime.datetime", - "timestamp": 1648801425.0 - } -} \ No newline at end of file + "job_id": "my_job_id" +} diff --git a/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.repr b/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.repr index 3a74c9a4e90..4ce4de0e34b 100644 --- a/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.repr +++ b/cirq-google/cirq_google/json_test_data/cirq.google.EngineResult.repr @@ -1 +1 @@ -cirq_google.EngineResult(params=cirq.ParamResolver({sympy.Symbol('a'): 0.5}), records={'m': np.array([[[True, True, False, True, False]], [[False, True, True, False, False]], [[True, False, True, False, True]]], dtype=np.dtype('bool'))}, job_id='my_job_id', job_finished_time=datetime.datetime(2022, 4, 1, 8, 23, 45, tzinfo=datetime.timezone.utc)) +cirq_google.EngineResult(params=cirq.ParamResolver({sympy.Symbol('a'): 0.5}), records={'m': np.array([[[True, True, False, True, False]], [[False, True, True, False, False]], [[True, False, True, False, True]]], dtype=np.dtype('bool'))}, job_id='my_job_id') From ee4290a1b4e57daf34a6987b023bc55deb838b2f Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Tue, 23 Sep 2025 13:08:58 -0700 Subject: [PATCH 4/4] lint --- cirq-google/cirq_google/engine/engine_result.py | 1 - cirq-google/cirq_google/engine/simulated_local_job.py | 1 - 2 files changed, 2 deletions(-) diff --git a/cirq-google/cirq_google/engine/engine_result.py b/cirq-google/cirq_google/engine/engine_result.py index f4c9c72d5d8..fba207e4d59 100644 --- a/cirq-google/cirq_google/engine/engine_result.py +++ b/cirq-google/cirq_google/engine/engine_result.py @@ -14,7 +14,6 @@ from __future__ import annotations -import datetime from typing import Any, Mapping, TYPE_CHECKING from cirq import study diff --git a/cirq-google/cirq_google/engine/simulated_local_job.py b/cirq-google/cirq_google/engine/simulated_local_job.py index 4580ae825d3..7026ca641a1 100644 --- a/cirq-google/cirq_google/engine/simulated_local_job.py +++ b/cirq-google/cirq_google/engine/simulated_local_job.py @@ -18,7 +18,6 @@ from __future__ import annotations import concurrent.futures -import datetime from typing import cast, Sequence import duet