Skip to content
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

Split the simulators' creation of ActOnArgs and iteration #3970

Merged
merged 52 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8ad4224
Move MPSSimulator to use act_on
tonybruguier Mar 20, 2021
ffd7b86
Add axes to mps
daxfohl Mar 23, 2021
6a28c01
Finish act-on for mps
daxfohl Mar 23, 2021
ca0a765
lint
daxfohl Mar 23, 2021
988d7ae
Add a copy method for all act_on_args
daxfohl Mar 23, 2021
b1774b7
Split creation of act_on_args and iteration
daxfohl Mar 24, 2021
bfa7ed0
remove the empty yields
daxfohl Mar 24, 2021
180bb67
Fix most unit tests
daxfohl Mar 24, 2021
25efdad
Change sparse simulator to use act_on_args in _run.
daxfohl Mar 24, 2021
49f4ae4
Fix clifford simulator
daxfohl Mar 24, 2021
d11d34f
format
daxfohl Mar 24, 2021
0ee6526
optimize imports
daxfohl Mar 24, 2021
f7f792a
Address PR comments
daxfohl Mar 25, 2021
11ac1d2
Merge branch 'master' into mps
daxfohl Mar 25, 2021
3f6d0e6
Unit test
daxfohl Mar 25, 2021
6c91dd8
Formatting
daxfohl Mar 25, 2021
39117a7
Merge branch 'mps' into spliterate
daxfohl Mar 25, 2021
1a5fea4
Merge branch 'master' into spliterate
daxfohl Mar 25, 2021
0c8763e
Rename, format
daxfohl Mar 25, 2021
ccc294c
Fix docs
daxfohl Mar 25, 2021
0edf566
Update quantum teleportation
daxfohl Mar 25, 2021
31fc327
Update quantum teleportation
daxfohl Mar 25, 2021
838d103
Update quantum teleportation
daxfohl Mar 25, 2021
f664e9d
Make the QubitOrder arg optional
daxfohl Mar 25, 2021
5a35ca9
Fix the engine_simulator.py overrides
daxfohl Mar 25, 2021
2d0ee42
Fix the engine_simulator.py overrides
daxfohl Mar 25, 2021
22b3b92
Fix the engine_simulator.py overrides
daxfohl Mar 25, 2021
5b98a6b
Fix coverage check
daxfohl Mar 25, 2021
f970a38
Change quantum teleportation example to be generic across simulators.
daxfohl Mar 28, 2021
1fd8e8c
Change quantum teleportation example to be generic across simulators.
daxfohl Mar 28, 2021
45cfdba
Change qubit_order to an explicit ordering of qubits.
daxfohl Mar 28, 2021
b34ac3a
Clean PR issues
daxfohl Apr 3, 2021
c9f12db
Merge branch 'master' into spliterate
daxfohl Apr 3, 2021
80b4202
Fix type check
daxfohl Apr 3, 2021
645988e
Fix unit test
daxfohl Apr 3, 2021
3ea6c69
Spelling
daxfohl Apr 4, 2021
2102af3
small changes
daxfohl Apr 5, 2021
637d88b
Merge remote-tracking branch 'origin/spliterate' into spliterate
daxfohl Apr 5, 2021
452a950
test change
daxfohl Apr 5, 2021
d1a42ad
make _core_iterator.sim_state naming consistent
daxfohl Apr 10, 2021
6465a23
Allow create_act_on_args to accept an ActOnArgs parameter, and return…
daxfohl Apr 10, 2021
814e82a
Merge branch 'master' into spliterate
daxfohl Apr 11, 2021
2fe1e8a
Add tests for `.simulate(ActOnArgs)`.
daxfohl Apr 11, 2021
cfb711e
Add tests for `.simulate(ActOnArgs)`.
daxfohl Apr 11, 2021
e2063df
lint
daxfohl Apr 11, 2021
8913bda
Plop qubits and qubit_map into ActOnArgs instead of passing together …
daxfohl Apr 11, 2021
d195016
Change qubits param to Sequence. Clean up teleportation example.
daxfohl Apr 12, 2021
739d69e
Merge branch 'master' into spliterate
daxfohl Apr 15, 2021
5ad813c
PR comments:
daxfohl Apr 19, 2021
f319a22
format/lint
daxfohl Apr 19, 2021
e5ff9fd
Merge branch 'master' into spliterate
daxfohl Apr 20, 2021
0e7ee06
format
daxfohl Apr 20, 2021
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
103 changes: 58 additions & 45 deletions cirq/contrib/quimb/mps_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
https://arxiv.org/abs/2002.07730
"""

import dataclasses
import math
from typing import Any, Dict, List, Iterator, Optional, Sequence, Set, TYPE_CHECKING, Iterable
from typing import Any, Dict, List, Optional, Sequence, Set, TYPE_CHECKING, Iterable, Union

import dataclasses
import numpy as np
import quimb.tensor as qtn

Expand Down Expand Up @@ -54,7 +54,9 @@ class MPSOptions:

class MPSSimulator(
simulator.SimulatesSamples,
simulator.SimulatesIntermediateState['MPSSimulatorStepResult', 'MPSTrialResult', 'MPSState'],
simulator.SimulatesIntermediateState[
'MPSSimulatorStepResult', 'MPSTrialResult', 'MPSState', 'MPSState'
],
):
"""An efficient simulator for MPS circuits."""

Expand Down Expand Up @@ -82,58 +84,68 @@ def __init__(
self.simulation_options = simulation_options
self.grouping = grouping

def _base_iterator(
self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: int
) -> Iterator['MPSSimulatorStepResult']:
"""Iterator over MPSSimulatorStepResult from Moments of a Circuit
def create_act_on_args(
self,
initial_state: Union[int, 'MPSState'],
qubits: Sequence['cirq.Qid'],
) -> 'MPSState':
"""Creates MPSState args for simulating the Circuit.

Args:
circuit: The circuit to simulate.
qubit_order: Determines the canonical ordering of the qubits. This
is often used in specifying the initial state, i.e. the
ordering of the computational basis states.
initial_state: The initial state for the simulation in the
computational basis. Represented as a big endian int.
qubits: Determines the canonical ordering of the qubits. This
is often used in specifying the initial state, i.e. the
ordering of the computational basis states.

Yields:
MPSStepResult from simulating a Moment of the Circuit.
Returns:
MPSState args for simulating the Circuit.
"""
qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(circuit.all_qubits())
if isinstance(initial_state, MPSState):
return initial_state

return MPSState(
qubits=qubits,
prng=self.prng,
simulation_options=self.simulation_options,
grouping=self.grouping,
initial_state=initial_state,
)

qubit_map = {q: i for i, q in enumerate(qubits)}
def _core_iterator(
self,
circuit: circuits.Circuit,
sim_state: 'MPSState',
):
"""Iterator over MPSSimulatorStepResult from Moments of a Circuit

Args:
circuit: The circuit to simulate.
sim_state: The initial state args for the simulation in the
computational basis.

Yields:
MPSStepResult from simulating a Moment of the Circuit.
"""
if len(circuit) == 0:
yield MPSSimulatorStepResult(
measurements={},
state=MPSState(
qubit_map,
self.prng,
self.simulation_options,
self.grouping,
initial_state=initial_state,
),
measurements=sim_state.log_of_measurement_results, state=sim_state
)
return

state = MPSState(
qubit_map,
self.prng,
self.simulation_options,
self.grouping,
initial_state=initial_state,
)

noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits()))
for op_tree in noisy_moments:
for op in flatten_to_ops(op_tree):
if protocols.is_measurement(op) or protocols.has_mixture(op):
state.axes = tuple(qubit_map[qubit] for qubit in op.qubits)
protocols.act_on(op, state)
sim_state.axes = tuple(sim_state.qubit_map[qubit] for qubit in op.qubits)
protocols.act_on(op, sim_state)
else:
raise NotImplementedError(f"Unrecognized operation: {op!r}")

yield MPSSimulatorStepResult(measurements=state.log_of_measurement_results, state=state)
state.log_of_measurement_results.clear()
yield MPSSimulatorStepResult(
measurements=sim_state.log_of_measurement_results, state=sim_state
)
sim_state.log_of_measurement_results.clear()

def _create_simulator_trial_result(
self,
Expand Down Expand Up @@ -286,7 +298,7 @@ class MPSState(ActOnArgs):

def __init__(
self,
qubit_map: Dict['cirq.Qid', int],
qubits: Sequence['cirq.Qid'],
prng: np.random.RandomState,
simulation_options: MPSOptions = MPSOptions(),
grouping: Optional[Dict['cirq.Qid', int]] = None,
Expand All @@ -297,7 +309,9 @@ def __init__(
"""Creates and MPSState

Args:
qubit_map: A map from Qid to an integer that uniquely identifies it.
qubits: Determines the canonical ordering of the qubits. This
is often used in specifying the initial state, i.e. the
ordering of the computational basis states.
prng: A random number generator, used to simulate measurements.
simulation_options: Numerical options for the simulation.
grouping: How to group qubits together, if None all are individual.
Expand All @@ -307,8 +321,8 @@ def __init__(
log_of_measurement_results: A mutable object that measurements are
being recorded into.
"""
super().__init__(prng, axes, log_of_measurement_results)
self.qubit_map = qubit_map
super().__init__(prng, qubits, axes, log_of_measurement_results)
qubit_map = self.qubit_map
self.grouping = qubit_map if grouping is None else grouping
if self.grouping.keys() != self.qubit_map.keys():
raise ValueError('Grouping must cover exactly the qubits.')
Expand Down Expand Up @@ -364,10 +378,10 @@ def _value_equality_values_(self) -> Any:

def copy(self) -> 'MPSState':
state = MPSState(
self.qubit_map,
self.prng,
self.simulation_options,
self.grouping,
qubits=self.qubits,
prng=self.prng,
simulation_options=self.simulation_options,
grouping=self.grouping,
)
state.M = [x.copy() for x in self.M]
state.estimated_gate_error_list = self.estimated_gate_error_list
Expand Down Expand Up @@ -584,6 +598,5 @@ def perform_measurement(

def _perform_measurement(self) -> List[int]:
"""Measures the axes specified by the simulator."""
qubit_map_inv = {v: k for k, v in self.qubit_map.items()}
qubits = [qubit_map_inv[key] for key in self.axes]
qubits = [self.qubits[key] for key in self.axes]
return self.perform_measurement(qubits, self.prng)
29 changes: 23 additions & 6 deletions cirq/contrib/quimb/mps_simulator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,23 @@ def test_cnot_flipped():
)


def test_act_on_args():
q0, q1 = qubit_order = cirq.LineQubit.range(2)
circuit = cirq.Circuit(cirq.CNOT(q1, q0))
mps_simulator = ccq.mps_simulator.MPSSimulator()
ref_simulator = cirq.Simulator()
for initial_state in range(4):
args = mps_simulator.create_act_on_args(initial_state=initial_state, qubits=(q0, q1))
actual = mps_simulator.simulate(circuit, qubit_order=qubit_order, initial_state=args)
expected = ref_simulator.simulate(
circuit, qubit_order=qubit_order, initial_state=initial_state
)
np.testing.assert_allclose(
actual.final_state.to_numpy(), expected.final_state_vector, atol=1e-4
)
assert len(actual.measurements) == 0


def test_three_qubits():
q0, q1, q2 = cirq.LineQubit.range(3)
circuit = cirq.Circuit(cirq.CCX(q0, q1, q2))
Expand Down Expand Up @@ -257,7 +274,7 @@ def test_measurement_str():
def test_trial_result_str():
q0 = cirq.LineQubit(0)
final_simulator_state = ccq.mps_simulator.MPSState(
qubit_map={q0: 0},
qubits=(q0,),
prng=value.parse_random_state(0),
simulation_options=ccq.mps_simulator.MPSOptions(),
)
Expand All @@ -278,7 +295,7 @@ def test_trial_result_str():

def test_empty_step_result():
q0 = cirq.LineQubit(0)
state = ccq.mps_simulator.MPSState(qubit_map={q0: 0}, prng=value.parse_random_state(0))
state = ccq.mps_simulator.MPSState(qubits=(q0,), prng=value.parse_random_state(0))
step_result = ccq.mps_simulator.MPSSimulatorStepResult(state, measurements={'0': [1]})
assert (
str(step_result)
Expand All @@ -292,17 +309,17 @@ def test_empty_step_result():
def test_state_equal():
q0, q1 = cirq.LineQubit.range(2)
state0 = ccq.mps_simulator.MPSState(
qubit_map={q0: 0},
qubits=(q0,),
prng=value.parse_random_state(0),
simulation_options=ccq.mps_simulator.MPSOptions(cutoff=1e-3, sum_prob_atol=1e-3),
)
state1a = ccq.mps_simulator.MPSState(
qubit_map={q1: 0},
qubits=(q1,),
prng=value.parse_random_state(0),
simulation_options=ccq.mps_simulator.MPSOptions(cutoff=1e-3, sum_prob_atol=1e-3),
)
state1b = ccq.mps_simulator.MPSState(
qubit_map={q1: 0},
qubits=(q1,),
prng=value.parse_random_state(0),
simulation_options=ccq.mps_simulator.MPSOptions(cutoff=1729.0, sum_prob_atol=1e-3),
)
Expand Down Expand Up @@ -500,7 +517,7 @@ def test_state_copy():

def test_state_act_on_args_initializer():
s = ccq.mps_simulator.MPSState(
qubit_map={cirq.LineQubit(0): 0},
qubits=(cirq.LineQubit(0),),
prng=np.random.RandomState(0),
axes=[2],
log_of_measurement_results={'test': 4},
Expand Down
42 changes: 22 additions & 20 deletions cirq/google/calibration/engine_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Callable,
Dict,
Iterable,
Iterator,
List,
Optional,
Sequence,
Expand All @@ -14,38 +13,35 @@
import numpy as np

from cirq.circuits import Circuit, PointOptimizer, PointOptimizationSummary
from cirq.google.calibration.phased_fsim import (
FloquetPhasedFSimCalibrationRequest,
PhaseCalibratedFSimGate,
IncompatibleMomentError,
PhasedFSimCalibrationRequest,
PhasedFSimCalibrationResult,
PhasedFSimCharacterization,
SQRT_ISWAP_PARAMETERS,
try_convert_sqrt_iswap_to_fsim,
)
from cirq.ops import (
FSimGate,
Gate,
MeasurementGate,
Operation,
PhasedFSimGate,
Qid,
QubitOrderOrList,
SingleQubitGate,
WaitGate,
)
from cirq.sim import (
Simulator,
SimulatesSamples,
SimulatesIntermediateStateVector,
StateVectorStepResult,
ActOnStateVectorArgs,
)
from cirq.study import ParamResolver
from cirq.value import RANDOM_STATE_OR_SEED_LIKE, parse_random_state

from cirq.google.calibration.phased_fsim import (
FloquetPhasedFSimCalibrationRequest,
PhaseCalibratedFSimGate,
IncompatibleMomentError,
PhasedFSimCalibrationRequest,
PhasedFSimCalibrationResult,
PhasedFSimCharacterization,
SQRT_ISWAP_PARAMETERS,
try_convert_sqrt_iswap_to_fsim,
)


ParametersDriftGenerator = Callable[[Qid, Qid, FSimGate], PhasedFSimCharacterization]
PhasedFsimDictParameters = Dict[
Tuple[Qid, Qid], Union[Dict[str, float], PhasedFSimCharacterization]
Expand Down Expand Up @@ -395,14 +391,20 @@ def _run(
converted = _convert_to_circuit_with_drift(self, circuit)
return self._simulator._run(converted, param_resolver, repetitions)

def _base_iterator(
def _core_iterator(
self,
circuit: Circuit,
qubit_order: QubitOrderOrList,
initial_state: Any,
) -> Iterator[StateVectorStepResult]:
sim_state: Any,
):
daxfohl marked this conversation as resolved.
Show resolved Hide resolved
converted = _convert_to_circuit_with_drift(self, circuit)
return self._simulator._base_iterator(converted, qubit_order, initial_state)
return self._simulator._core_iterator(converted, sim_state)

def create_act_on_args(
self,
initial_state: Union[int, ActOnStateVectorArgs],
qubits: Sequence[Qid],
):
return self._simulator.create_act_on_args(initial_state, qubits)


class _PhasedFSimConverter(PointOptimizer):
Expand Down
Loading