Skip to content

Lazily create TrialResult.final_simulator_state #4317

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

Merged
merged 8 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
18 changes: 9 additions & 9 deletions cirq-core/cirq/contrib/quimb/mps_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,23 +125,21 @@ def _create_simulator_trial_result(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state: 'MPSState',
final_step_result: 'MPSSimulatorStepResult',
) -> 'MPSTrialResult':
"""Creates a single trial results with the measurements.

Args:
circuit: The circuit to simulate.
param_resolver: A ParamResolver for determining values of
Symbols.
params: A ParamResolver for determining values of Symbols.
measurements: A dictionary from measurement key (e.g. qubit) to the
actual measurement array.
final_simulator_state: The final state of the simulator.
final_step_result: The final step result of the simulation.

Returns:
A single result.
"""
return MPSTrialResult(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
params=params, measurements=measurements, final_step_result=final_step_result
)


Expand All @@ -152,13 +150,15 @@ def __init__(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state: 'MPSState',
final_step_result: 'MPSSimulatorStepResult',
) -> None:
super().__init__(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
params=params, measurements=measurements, final_step_result=final_step_result
)

self.final_state = final_simulator_state
@property
def final_state(self):
return self._final_simulator_state

def __str__(self) -> str:
samples = super().__str__()
Expand Down
8 changes: 5 additions & 3 deletions cirq-core/cirq/contrib/quimb/mps_simulator_test.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import itertools
import math
from unittest import mock

import numpy as np
import pytest
import sympy

import cirq
from cirq import value
import cirq.contrib.quimb as ccq
import cirq.experiments.google_v2_supremacy_circuit as supremacy_v2
from cirq import value


def assert_same_output_as_dense(circuit, qubit_order, initial_state=0, grouping=None):
Expand Down Expand Up @@ -252,7 +253,8 @@ def test_measurement_str():

def test_trial_result_str():
q0 = cirq.LineQubit(0)
final_simulator_state = ccq.mps_simulator.MPSState(
final_step_result = mock.Mock(cirq.StepResult)
final_step_result._simulator_state.return_value = ccq.mps_simulator.MPSState(
qubits=(q0,),
prng=value.parse_random_state(0),
simulation_options=ccq.mps_simulator.MPSOptions(),
Expand All @@ -262,7 +264,7 @@ def test_trial_result_str():
ccq.mps_simulator.MPSTrialResult(
params=cirq.ParamResolver({}),
measurements={'m': np.array([[1]])},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)
== """measurements: m=1
Expand Down
12 changes: 7 additions & 5 deletions cirq-core/cirq/sim/clifford/clifford_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ def _create_simulator_trial_result(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state,
final_step_result: 'CliffordSimulatorStepResult',
):

return CliffordTrialResult(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
params=params, measurements=measurements, final_step_result=final_step_result
)


Expand All @@ -118,13 +118,15 @@ def __init__(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state: 'CliffordState',
final_step_result: 'CliffordSimulatorStepResult',
) -> None:
super().__init__(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
params=params, measurements=measurements, final_step_result=final_step_result
)

self.final_state = final_simulator_state
@property
def final_state(self):
return self._final_simulator_state

def __str__(self) -> str:
samples = super().__str__()
Expand Down
12 changes: 8 additions & 4 deletions cirq-core/cirq/sim/clifford/clifford_simulator_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import itertools
from unittest import mock

import numpy as np
import pytest
import sympy
Expand Down Expand Up @@ -208,13 +210,14 @@ def test_clifford_state_initial_state():

def test_clifford_trial_result_repr():
q0 = cirq.LineQubit(0)
final_simulator_state = cirq.CliffordState(qubit_map={q0: 0})
final_step_result = mock.Mock(cirq.CliffordSimulatorStepResult)
final_step_result._simulator_state.return_value = cirq.CliffordState(qubit_map={q0: 0})
assert (
repr(
cirq.CliffordTrialResult(
params=cirq.ParamResolver({}),
measurements={'m': np.array([[1]])},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)
== "cirq.SimulationTrialResult(params=cirq.ParamResolver({}), "
Expand All @@ -225,13 +228,14 @@ def test_clifford_trial_result_repr():

def test_clifford_trial_result_str():
q0 = cirq.LineQubit(0)
final_simulator_state = cirq.CliffordState(qubit_map={q0: 0})
final_step_result = mock.Mock(cirq.CliffordSimulatorStepResult)
final_step_result._simulator_state.return_value = cirq.CliffordState(qubit_map={q0: 0})
assert (
str(
cirq.CliffordTrialResult(
params=cirq.ParamResolver({}),
measurements={'m': np.array([[1]])},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)
== "measurements: m=1\n"
Expand Down
23 changes: 14 additions & 9 deletions cirq-core/cirq/sim/density_matrix_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ def _create_simulator_trial_result(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state: 'DensityMatrixSimulatorState',
final_step_result: 'DensityMatrixStepResult',
) -> 'DensityMatrixTrialResult':
return DensityMatrixTrialResult(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
params=params, measurements=measurements, final_step_result=final_step_result
)

# TODO(#4209): Deduplicate with identical code in sparse_simulator.
Expand Down Expand Up @@ -423,22 +423,27 @@ class DensityMatrixTrialResult(simulator.SimulationTrialResult):
measurement gate.)
final_simulator_state: The final simulator state of the system after the
trial finishes.
final_density_matrix: The final density matrix of the system.
"""

def __init__(
self,
params: study.ParamResolver,
measurements: Dict[str, np.ndarray],
final_simulator_state: DensityMatrixSimulatorState,
final_step_result: DensityMatrixStepResult,
) -> None:
super().__init__(
params=params, measurements=measurements, final_simulator_state=final_simulator_state
)
size = np.prod(protocols.qid_shape(self), dtype=int)
self.final_density_matrix = np.reshape(
final_simulator_state.density_matrix.copy(), (size, size)
params=params, measurements=measurements, final_step_result=final_step_result
)
self._final_density_matrix: Optional[np.ndarray] = None

@property
def final_density_matrix(self):
if self._final_density_matrix is None:
size = np.prod(protocols.qid_shape(self), dtype=int)
self._final_density_matrix = np.reshape(
self._final_simulator_state.density_matrix.copy(), (size, size)
)
return self._final_density_matrix

def _value_equality_values_(self) -> Any:
measurements = {k: v.tolist() for k, v in sorted(self.measurements.items())}
Expand Down
66 changes: 49 additions & 17 deletions cirq-core/cirq/sim/density_matrix_simulator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
# 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 Type
from unittest import mock
import itertools
import platform
import random
from typing import Type
from unittest import mock

import numpy as np
import pytest
import sympy
Expand Down Expand Up @@ -998,61 +1000,65 @@ def test_density_matrix_simulator_state_repr():

def test_density_matrix_trial_result_eq():
q0 = cirq.LineQubit(0)
final_simulator_state = cirq.DensityMatrixSimulatorState(
final_step_result = mock.Mock(cirq.StepResult)
final_step_result._simulator_state.return_value = cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((2, 2)) * 0.5, qubit_map={q0: 0}
)
eq = cirq.testing.EqualsTester()
eq.add_equality_group(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({}),
measurements={},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
),
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({}),
measurements={},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
),
)
eq.add_equality_group(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({'s': 1}),
measurements={},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)
eq.add_equality_group(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({'s': 1}),
measurements={'m': np.array([[1]])},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)


def test_density_matrix_trial_result_qid_shape():
q0, q1 = cirq.LineQubit.range(2)
final_step_result = mock.Mock(cirq.StepResult)
final_step_result._simulator_state.return_value = cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((4, 4)) / 4, qubit_map={q0: 0, q1: 1}
)
assert (
cirq.qid_shape(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({}),
measurements={},
final_simulator_state=cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((4, 4)) / 4, qubit_map={q0: 0, q1: 1}
),
final_step_result=final_step_result,
),
)
== (2, 2)
)
q0, q1 = cirq.LineQid.for_qid_shape((3, 4))
final_step_result._simulator_state.return_value = cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((12, 12)) / 12, qubit_map={q0: 0, q1: 1}
)
assert (
cirq.qid_shape(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({}),
measurements={},
final_simulator_state=cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((12, 12)) / 12, qubit_map={q0: 0, q1: 1}
),
final_step_result=final_step_result,
),
)
== (3, 4)
Expand All @@ -1061,15 +1067,16 @@ def test_density_matrix_trial_result_qid_shape():

def test_density_matrix_trial_result_repr():
q0 = cirq.LineQubit(0)
final_simulator_state = cirq.DensityMatrixSimulatorState(
final_step_result = mock.Mock(cirq.StepResult)
final_step_result._simulator_state.return_value = cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((2, 2)) * 0.5, qubit_map={q0: 0}
)
assert (
repr(
cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({'s': 1}),
measurements={'m': np.array([[1]])},
final_simulator_state=final_simulator_state,
final_step_result=final_step_result,
)
)
== "cirq.DensityMatrixTrialResult("
Expand Down Expand Up @@ -1166,11 +1173,12 @@ def test_works_on_pauli_string():

def test_density_matrix_trial_result_str():
q0 = cirq.LineQubit(0)
final_simulator_state = cirq.DensityMatrixSimulatorState(
final_step_result = mock.Mock(cirq.StepResult)
final_step_result._simulator_state.return_value = cirq.DensityMatrixSimulatorState(
density_matrix=np.ones((2, 2)) * 0.5, qubit_map={q0: 0}
)
result = cirq.DensityMatrixTrialResult(
params=cirq.ParamResolver({}), measurements={}, final_simulator_state=final_simulator_state
params=cirq.ParamResolver({}), measurements={}, final_step_result=final_step_result
)

# numpy varies whitespace in its representation for different versions
Expand Down Expand Up @@ -1527,3 +1535,27 @@ def test_density_matrices_same_with_or_without_split_untangled_states():
sim = cirq.DensityMatrixSimulator(split_untangled_states=True)
result2 = sim.simulate(circuit).final_density_matrix
assert np.allclose(result1, result2)


def test_large_untangled_okay():
circuit = cirq.Circuit()
for i in range(59):
for _ in range(9):
circuit.append(cirq.X(cirq.LineQubit(i)))
circuit.append(cirq.measure(cirq.LineQubit(i)))

# Validate this can't be allocated with entangled state
if platform.system() != "Windows":
with pytest.raises(MemoryError, match='Unable to allocate'):
_ = cirq.DensityMatrixSimulator(split_untangled_states=False).simulate(circuit)

# Validate a simulation run
result = cirq.DensityMatrixSimulator(split_untangled_states=True).simulate(circuit)
assert set(result._final_step_result._qubits) == set(cirq.LineQubit.range(59))
# _ = result.final_density_matrix hangs (as expected)

# Validate a trial run and sampling
result = cirq.DensityMatrixSimulator(split_untangled_states=True).run(circuit, repetitions=1000)
assert len(result.measurements) == 59
assert len(result.measurements['0']) == 1000
assert (result.measurements['0'] == np.full(1000, 1)).all()
Loading