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

Sample independent qubit sets without merging state space #4110

Merged
merged 161 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from 151 commits
Commits
Show all changes
161 commits
Select commit Hold shift + click to select a range
293374d
split
daxfohl May 6, 2021
4faff08
Allow config param split_entangled_states
daxfohl May 6, 2021
8c202a4
default split to off
daxfohl May 7, 2021
54f1eea
ensure consistent_act_on circuits have a qubit.
daxfohl May 7, 2021
265d939
lint
daxfohl May 7, 2021
099ecc5
lint
daxfohl May 7, 2021
a698893
mps
daxfohl May 7, 2021
251eeb4
lint
daxfohl May 7, 2021
a255905
lint
daxfohl May 7, 2021
6f58842
run sparse by default
daxfohl May 7, 2021
b7254f9
fix tests
daxfohl May 7, 2021
79e77b2
fix tests
daxfohl May 7, 2021
4d301e5
fix tests
daxfohl May 7, 2021
181d5fb
most of sparse and dm
daxfohl May 8, 2021
f982731
clifford
daxfohl May 8, 2021
1ee3468
sim_base
daxfohl May 8, 2021
994d9d4
sim_base
daxfohl May 8, 2021
fe2761c
mps
daxfohl May 8, 2021
3c472b6
turn off on experiments with rounding error
daxfohl May 9, 2021
c4bd708
fix tests
daxfohl May 9, 2021
1ed1f2e
fix tests
daxfohl May 9, 2021
d0cd4f2
fix testsCreate base step result
daxfohl May 11, 2021
ab1f63c
clifford
daxfohl May 11, 2021
bedb9ec
mps
daxfohl May 11, 2021
8b34b11
mps
daxfohl May 11, 2021
58ed8fa
mps
daxfohl May 11, 2021
ba93627
Merge branch 'master' into split
daxfohl May 11, 2021
027e1b6
Merge branch 'split' into sample
daxfohl May 11, 2021
f44b863
Merge branch 'sample' into sample2
daxfohl May 11, 2021
cba2940
tableau
daxfohl May 11, 2021
95683b7
test simulator
daxfohl May 11, 2021
e472b5a
test simulator
daxfohl May 11, 2021
c5e2485
Update simulator_base.py
daxfohl May 11, 2021
44791ae
Drop mps/join
daxfohl May 11, 2021
febd6ab
Merge branch 'split' of https://github.com/daxfohl/Cirq into split
daxfohl May 11, 2021
a77314a
Merge branch 'master' into split
daxfohl May 11, 2021
6613a05
Fix clifford extract
daxfohl May 12, 2021
10cffe3
Merge branch 'master' into split
daxfohl May 12, 2021
b886923
Merge branch 'split' into sample2
daxfohl May 12, 2021
0c02c2b
lint
daxfohl May 12, 2021
d88a3c6
simplify index
daxfohl May 12, 2021
d2a46f1
Add qubits to base class
daxfohl May 12, 2021
72d8df6
Fix clifford sampling
daxfohl May 12, 2021
da785b6
Fix _sim_state_values
daxfohl May 12, 2021
ffccd8b
fix tostring tests, format
daxfohl May 12, 2021
462a842
remove split/join from ch-form
daxfohl May 14, 2021
ce08aae
Merge branch 'master' into split
daxfohl May 14, 2021
97201d9
Merge branch 'split' into sample
daxfohl May 14, 2021
592d202
remove split/join from ch-form
daxfohl May 14, 2021
bc8cf25
push merged state to base layer
daxfohl May 15, 2021
0db5b2f
lint
daxfohl May 16, 2021
a578685
mypy
daxfohl May 16, 2021
ba81f7c
mypy
daxfohl May 16, 2021
b7288f4
mypy
daxfohl May 16, 2021
d56ebd3
Add default arg for zero qubit circuits
daxfohl May 26, 2021
0af64a5
Merge branch 'master' into split
daxfohl May 26, 2021
352eed4
Have last repetition reuse original state repr
daxfohl May 26, 2021
f51a811
Merge branch 'split' of https://github.com/daxfohl/Cirq into split
daxfohl May 26, 2021
766d4b8
Remove cast
daxfohl May 26, 2021
1e3a208
Split all pure initial states by default
daxfohl May 26, 2021
8629086
Detangle on reset channels
daxfohl Jun 3, 2021
f37d5a0
docstrings
daxfohl Jun 3, 2021
dd1fbf8
docstrings
daxfohl Jun 3, 2021
26402b0
docstrings
daxfohl Jun 3, 2021
ce93863
docstrings
daxfohl Jun 3, 2021
1e83ee6
Merge branch 'master' into split
daxfohl Jun 4, 2021
9828350
fix merge
daxfohl Jun 4, 2021
cfa3ada
lint
daxfohl Jun 4, 2021
fe16073
Add unit test for integer states
daxfohl Jun 4, 2021
b2fb89c
format
daxfohl Jun 4, 2021
184d0d9
Add tests for splitting and joining
daxfohl Jun 4, 2021
1bc5176
remove unnecessary qubits param
daxfohl Jun 5, 2021
f874bcd
Clean up default args
daxfohl Jun 5, 2021
e4c5fcc
Fix failing test
daxfohl Jun 5, 2021
bd2f726
Add ActOnArgsContainer
daxfohl Jun 5, 2021
534a59e
Add ActOnArgsContainer
daxfohl Jun 5, 2021
d701f5e
Clean up tests
daxfohl Jun 6, 2021
6f01a77
Clean up tests
daxfohl Jun 6, 2021
e42892c
Clean up tests
daxfohl Jun 6, 2021
1ad4cf8
format
daxfohl Jun 6, 2021
5420919
Fix tests and coverage
daxfohl Jun 6, 2021
8957e9b
Add OperationTarget interface
daxfohl Jun 6, 2021
50f99b6
Fix unit tests
daxfohl Jun 6, 2021
c372796
mypy, lint, mocks, coverage
daxfohl Jun 6, 2021
9f01c2d
coverage
daxfohl Jun 6, 2021
6af822c
Merge branch 'master' into split
daxfohl Jun 6, 2021
cb93306
Merge branch 'split' into sample
daxfohl Jun 6, 2021
7a4b7fd
lint, tests
daxfohl Jun 6, 2021
c6562f9
lint, tests
daxfohl Jun 6, 2021
6917dd0
mypy
daxfohl Jun 6, 2021
1fc8bdf
mypy, tests
daxfohl Jun 6, 2021
dc6ecfc
remove test code
daxfohl Jun 6, 2021
24461f7
test
daxfohl Jun 6, 2021
f8e4989
dead code
daxfohl Jun 6, 2021
fe0362a
mocks
daxfohl Jun 6, 2021
5dc90dd
add log to container
daxfohl Jun 7, 2021
0860077
fix logs
daxfohl Jun 7, 2021
3922452
dead code
daxfohl Jun 7, 2021
5de0783
Merge branch 'split' into sample
daxfohl Jun 7, 2021
4134450
unit test
daxfohl Jun 7, 2021
1446ea0
unit test
daxfohl Jun 7, 2021
9a635c9
dead code
daxfohl Jun 7, 2021
6b1f23a
operationtarget samples
daxfohl Jun 7, 2021
98e2c55
StepResultBase
daxfohl Jun 7, 2021
1cf627f
Mock, format
daxfohl Jun 7, 2021
8a0675e
EmptyActOnArgs
daxfohl Jun 7, 2021
47a81e0
EmptyActOnArgs
daxfohl Jun 7, 2021
3066010
simplify dummyargs
daxfohl Jun 7, 2021
996be64
simplify dummyargs
daxfohl Jun 7, 2021
191a7e8
lint
daxfohl Jun 8, 2021
16a995f
Merge branch 'split' into sample
daxfohl Jun 8, 2021
278bcd3
Add [] to actonargs
daxfohl Jun 10, 2021
f9b2080
Merge branch 'master' into split
daxfohl Jun 10, 2021
9958740
rename _create_act_on_arg
daxfohl Jun 10, 2021
63fe48d
coverage
daxfohl Jun 10, 2021
4719f5f
coverage
daxfohl Jun 10, 2021
2f3b6f6
Default sparse sim to split=false
daxfohl Jun 12, 2021
eae56b1
format
daxfohl Jun 12, 2021
2993f28
Default sparse sim to split=false
daxfohl Jun 12, 2021
8217b07
Default density matrix sim to split=false
daxfohl Jun 12, 2021
ec50741
lint
daxfohl Jun 12, 2021
6653a54
lint
daxfohl Jun 14, 2021
df55deb
lint
daxfohl Jun 14, 2021
50e6978
lint
daxfohl Jun 14, 2021
d834de1
Merge branch 'master' into split
daxfohl Jun 14, 2021
78a1cc1
address review comments
daxfohl Jun 18, 2021
bc64bc6
Merge branch 'master' into temp
daxfohl Jun 19, 2021
c0647f2
lint
daxfohl Jun 19, 2021
41ebd25
Defaults back to split=false
daxfohl Jun 19, 2021
8537aba
add error if setting state when split is enabled
daxfohl Jun 19, 2021
2ccf2ab
Unit tests
daxfohl Jun 19, 2021
dbe38f5
coverage
daxfohl Jun 19, 2021
1d2b325
coverage
daxfohl Jun 19, 2021
da040e6
coverage
daxfohl Jun 19, 2021
145d52c
docs
daxfohl Jun 19, 2021
a1a71cc
Merge branch 'split' into test
daxfohl Jun 21, 2021
a90ad70
conflicts
daxfohl Jun 21, 2021
afd8d9d
conflicts
daxfohl Jun 21, 2021
c489e3d
cover
daxfohl Jun 21, 2021
edcbefc
Add qubits to bb84
daxfohl Jun 21, 2021
898dfa0
mergedsimstate private
daxfohl Jun 21, 2021
e52e560
q_set
daxfohl Jun 21, 2021
665f829
default to split=True
daxfohl Jun 21, 2021
19049aa
Allow set_state
daxfohl Jun 21, 2021
57c3a87
Allow set_state
daxfohl Jun 21, 2021
19a834c
Merge branch 'master' into sample
daxfohl Jun 21, 2021
8acd7b5
format
daxfohl Jun 21, 2021
f3862f5
Merge branch 'master' into sample
daxfohl Jul 2, 2021
7851145
fix merge
daxfohl Jul 2, 2021
460ac65
fix merge
daxfohl Jul 2, 2021
f16742b
maintain order in sampling for determinicity.
daxfohl Jul 3, 2021
1111cf0
Pydoc fixes
daxfohl Jul 9, 2021
bd43695
revert bb48 num_qubits change
daxfohl Jul 9, 2021
802958f
fix docstrings for set_state error
daxfohl Jul 9, 2021
da06988
Merge branch 'master' into sample
daxfohl Jul 9, 2021
c9a41d7
Remove duplicate sample declaration from ActOnArgs
daxfohl Jul 9, 2021
6e2cdff
Remove unnecessary split_untangled_states=True
daxfohl Jul 9, 2021
365e4bd
Reduce atol of dm/sv test
daxfohl Jul 9, 2021
d90e2dc
Add test for sim_state propagation from step_result
daxfohl Jul 9, 2021
bd2bf74
Add test for sim_state propagation from step_result
daxfohl Jul 9, 2021
b28f2aa
Merge branch 'master' into sample
CirqBot Jul 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions cirq-core/cirq/__init__.py
Expand Up @@ -398,6 +398,7 @@
StateVectorStepResult,
StateVectorTrialResult,
StepResult,
StepResultBase,
)

from cirq.study import (
Expand Down
65 changes: 31 additions & 34 deletions cirq-core/cirq/contrib/quimb/mps_simulator.py
Expand Up @@ -117,12 +117,9 @@ def _create_partial_act_on_args(

def _create_step_result(
self,
sim_state: 'MPSState',
qubit_map: Dict['cirq.Qid', int],
sim_state: 'cirq.OperationTarget[MPSState]',
):
return MPSSimulatorStepResult(
measurements=sim_state.log_of_measurement_results, state=sim_state
)
return MPSSimulatorStepResult(sim_state)

def _create_simulator_trial_result(
self,
Expand Down Expand Up @@ -169,22 +166,22 @@ def __str__(self) -> str:
return f'measurements: {samples}\noutput state: {final}'


class MPSSimulatorStepResult(simulator.StepResult['MPSState']):
class MPSSimulatorStepResult(simulator_base.StepResultBase['MPSState', 'MPSState']):
"""A `StepResult` that can perform measurements."""

def __init__(self, state, measurements):
def __init__(
self,
sim_state: 'cirq.OperationTarget[MPSState]',
):
"""Results of a step of the simulator.
Attributes:
state: A MPSState
measurements: A dictionary from measurement gate key to measurement
results, ordered by the qubits that the measurement operates on.
qubit_map: A map from the Qubits in the Circuit to the the index
of this qubit for a canonical ordering. This canonical ordering
is used to define the state vector (see the state_vector()
method).
sim_state: The qubit:ActOnArgs lookup for this step.
"""
self.measurements = measurements
self.state = state.copy()
super().__init__(sim_state)

@property
def state(self):
return self._merged_sim_state

def __str__(self) -> str:
def bitstring(vals):
Expand All @@ -204,24 +201,6 @@ def bitstring(vals):
def _simulator_state(self):
return self.state

def sample(
self,
qubits: List[ops.Qid],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:

measurements: List[int] = []

for _ in range(repetitions):
measurements.append(
self.state.perform_measurement(
qubits, value.parse_random_state(seed), collapse_state_vector=False
)
)

return np.array(measurements, dtype=int)


@value.value_equality
class MPSState(ActOnArgs):
Expand Down Expand Up @@ -537,3 +516,21 @@ def perform_measurement(
def _perform_measurement(self, qubits: Sequence['cirq.Qid']) -> List[int]:
"""Measures the axes specified by the simulator."""
return self.perform_measurement(qubits, self.prng)

def sample(
self,
qubits: Sequence[ops.Qid],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:

measurements: List[List[int]] = []

for _ in range(repetitions):
measurements.append(
self.perform_measurement(
qubits, value.parse_random_state(seed), collapse_state_vector=False
)
)

return np.array(measurements, dtype=int)
6 changes: 3 additions & 3 deletions cirq-core/cirq/contrib/quimb/mps_simulator_test.py
Expand Up @@ -274,11 +274,11 @@ def test_trial_result_str():

def test_empty_step_result():
q0 = cirq.LineQubit(0)
state = ccq.mps_simulator.MPSState(qubits=(q0,), prng=value.parse_random_state(0))
step_result = ccq.mps_simulator.MPSSimulatorStepResult(state, measurements={'0': [1]})
sim = ccq.mps_simulator.MPSSimulator()
step_result = next(sim.simulate_moment_steps(cirq.Circuit(cirq.measure(q0))))
assert (
str(step_result)
== """0=1
== """0=0
TensorNetwork([
Tensor(shape=(2,), inds=('i_0',), tags=set()),
])"""
Expand Down
Expand Up @@ -20,7 +20,7 @@ def test_estimate_parallel_two_qubit_xeb_fidelity_on_grid_no_noise(tmpdir):
two_qubit_gate = cirq.ISWAP ** 0.5
cycles = [5, 10, 15]
data_collection_id = collect_grid_parallel_two_qubit_xeb_data(
sampler=cirq.Simulator(seed=34310),
sampler=cirq.Simulator(seed=34310, split_untangled_states=False),
daxfohl marked this conversation as resolved.
Show resolved Hide resolved
qubits=qubits,
two_qubit_gate=two_qubit_gate,
num_circuits=2,
Expand Down Expand Up @@ -53,7 +53,9 @@ def test_estimate_parallel_two_qubit_xeb_fidelity_on_grid_depolarizing(tmpdir):
cycles = [5, 10, 15]
e = 0.01
data_collection_id = collect_grid_parallel_two_qubit_xeb_data(
sampler=cirq.DensityMatrixSimulator(noise=cirq.depolarize(e), seed=65008),
sampler=cirq.DensityMatrixSimulator(
noise=cirq.depolarize(e), seed=65008, split_untangled_states=False
daxfohl marked this conversation as resolved.
Show resolved Hide resolved
),
qubits=qubits,
two_qubit_gate=two_qubit_gate,
num_circuits=2,
Expand Down
Expand Up @@ -31,7 +31,7 @@ def __init__(self, p0: float, p1: float, seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE'
self.p0 = p0
self.p1 = p1
self.prng = cirq.value.parse_random_state(seed)
self.simulator = cirq.Simulator(seed=self.prng)
self.simulator = cirq.Simulator(seed=self.prng, split_untangled_states=False)
daxfohl marked this conversation as resolved.
Show resolved Hide resolved

def run_sweep(
self,
Expand Down
3 changes: 3 additions & 0 deletions cirq-core/cirq/protocols/act_on_protocol_test.py
Expand Up @@ -37,6 +37,9 @@ def copy(self):
def _act_on_fallback_(self, action, qubits, allow_decompose):
return self.fallback_result

def sample(self, qubits, repetitions=1, seed=None):
pass


op = cirq.X(cirq.LineQubit(0))

Expand Down
1 change: 1 addition & 0 deletions cirq-core/cirq/sim/__init__.py
Expand Up @@ -64,6 +64,7 @@
)

from cirq.sim.simulator_base import (
StepResultBase,
SimulatorBase,
)

Expand Down
15 changes: 12 additions & 3 deletions cirq-core/cirq/sim/act_on_args.py
Expand Up @@ -72,7 +72,7 @@ def __init__(
if log_of_measurement_results is None:
log_of_measurement_results = {}
self._qubits = tuple(qubits)
self.qubit_map = {q: i for i, q in enumerate(self.qubits)}
self.qubit_map = {q: i for i, q in enumerate(qubits)}
self._axes = tuple(axes)
self.prng = prng
self._log_of_measurement_results = log_of_measurement_results
Expand All @@ -89,9 +89,9 @@ def measure(self, qubits: Sequence['cirq.Qid'], key: str, invert_mask: Sequence[
"""
bits = self._perform_measurement(qubits)
corrected = [bit ^ (bit < 2 and mask) for bit, mask in zip(bits, invert_mask)]
if key in self.log_of_measurement_results:
if key in self._log_of_measurement_results:
raise ValueError(f"Measurement already logged to key {key!r}")
self.log_of_measurement_results[key] = corrected
self._log_of_measurement_results[key] = corrected

def get_axes(self, qubits: Sequence['cirq.Qid']) -> List[int]:
return [self.qubit_map[q] for q in qubits]
Expand Down Expand Up @@ -139,6 +139,15 @@ def log_of_measurement_results(self) -> Dict[str, Any]:
def qubits(self) -> Tuple['cirq.Qid', ...]:
return self._qubits

@abc.abstractmethod
def sample(
self,
qubits: Sequence['cirq.Qid'],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
"""Samples the qubits."""

def __getitem__(self: TSelf, item: Optional['cirq.Qid']) -> TSelf:
if item not in self.qubit_map:
raise IndexError(f'{item} not in {self.qubits}')
Expand Down
29 changes: 27 additions & 2 deletions cirq-core/cirq/sim/act_on_args_container.py
Expand Up @@ -20,10 +20,14 @@
Sequence,
Optional,
Iterator,
Tuple,
Any,
Tuple,
Set,
List,
)

import numpy as np

from cirq import ops
from cirq.sim.operation_target import OperationTarget
from cirq.sim.simulator import (
Expand Down Expand Up @@ -58,7 +62,8 @@ def __init__(
unentangled qubit sets independently and merging those states
at the end.
log_of_measurement_results: A mutable object that measurements are
being recorded into.
being recorded into. Edit it easily by calling
`ActOnStateVectorArgs.record_measurement_result`.
daxfohl marked this conversation as resolved.
Show resolved Hide resolved
"""
self.args = args
self._qubits = tuple(qubits)
Expand Down Expand Up @@ -122,6 +127,26 @@ def qubits(self) -> Tuple['cirq.Qid', ...]:
def log_of_measurement_results(self) -> Dict[str, Any]:
return self._log_of_measurement_results

def sample(
self,
qubits: List[ops.Qid],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
columns = []
selected_order: List[ops.Qid] = []
q_set = set(qubits)
for v in dict.fromkeys(self.args.values()):
qs = [q for q in v.qubits if q in q_set]
if any(qs):
column = v.sample(qs, repetitions, seed)
columns.append(column)
selected_order += qs
stacked = np.column_stack(columns)
qubit_map = {q: i for i, q in enumerate(selected_order)}
index_order = [qubit_map[q] for q in qubits]
return stacked[:, index_order]

def __getitem__(self, item: Optional['cirq.Qid']) -> TActOnArgs:
return self.args[item]

Expand Down
3 changes: 3 additions & 0 deletions cirq-core/cirq/sim/act_on_args_container_test.py
Expand Up @@ -64,6 +64,9 @@ def transpose_to_qubit_order(self, qubits: Sequence['cirq.Qid']) -> 'EmptyActOnA
logs=self.log_of_measurement_results,
)

def sample(self, qubits, repetitions=1, seed=None):
pass


q0, q1 = qs2 = cirq.LineQubit.range(2)

Expand Down
3 changes: 3 additions & 0 deletions cirq-core/cirq/sim/act_on_args_test.py
Expand Up @@ -25,6 +25,9 @@ def __init__(self):
def copy(self):
pass

def sample(self, qubits, repetitions=1, seed=None):
pass

def _perform_measurement(self, qubits):
return [5, 3]

Expand Down
15 changes: 15 additions & 0 deletions cirq-core/cirq/sim/act_on_density_matrix_args.py
Expand Up @@ -197,6 +197,21 @@ def transpose_to_qubit_order(
log_of_measurement_results=self.log_of_measurement_results,
)

def sample(
self,
qubits: Sequence['cirq.Qid'],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
indices = [self.qubit_map[q] for q in qubits]
return sim.sample_density_matrix(
self.target_tensor,
indices,
qid_shape=tuple(q.dimension for q in self.qubits),
repetitions=repetitions,
seed=seed,
)


def _strat_apply_channel_to_state(
action: Any, args: ActOnDensityMatrixArgs, qubits: Sequence['cirq.Qid']
Expand Down
15 changes: 15 additions & 0 deletions cirq-core/cirq/sim/act_on_state_vector_args.py
Expand Up @@ -255,6 +255,21 @@ def transpose_to_qubit_order(self, qubits: Sequence['cirq.Qid']) -> 'cirq.ActOnS
)
return new_args

def sample(
self,
qubits: Sequence['cirq.Qid'],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
indices = [self.qubit_map[q] for q in qubits]
return sim.sample_state_vector(
self.target_tensor,
indices,
qid_shape=tuple(q.dimension for q in self.qubits),
repetitions=repetitions,
seed=seed,
)


def _strat_act_on_state_vector_from_apply_unitary(
unitary_value: Any,
Expand Down
9 changes: 9 additions & 0 deletions cirq-core/cirq/sim/clifford/act_on_clifford_tableau_args.py
Expand Up @@ -111,6 +111,15 @@ def copy(self) -> 'cirq.ActOnCliffordTableauArgs':
log_of_measurement_results=self.log_of_measurement_results.copy(),
)

def sample(
self,
qubits: Sequence['cirq.Qid'],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
# Unnecessary for now but can be added later if there is a use case.
raise NotImplementedError()


def _strat_act_on_clifford_tableau_from_single_qubit_decompose(
val: Any, args: 'cirq.ActOnCliffordTableauArgs', qubits: Sequence['cirq.Qid']
Expand Down
16 changes: 16 additions & 0 deletions cirq-core/cirq/sim/clifford/act_on_stabilizer_ch_form_args.py
Expand Up @@ -16,6 +16,7 @@

import numpy as np

from cirq import value, ops, protocols
from cirq._compat import deprecated_parameter
from cirq.ops import common_gates, pauli_gates
from cirq.ops.clifford_gate import SingleQubitCliffordGate
Expand Down Expand Up @@ -106,6 +107,21 @@ def copy(self) -> 'cirq.ActOnStabilizerCHFormArgs':
log_of_measurement_results=self.log_of_measurement_results.copy(),
)

def sample(
self,
qubits: Sequence['cirq.Qid'],
repetitions: int = 1,
seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> np.ndarray:
measurements: Dict[str, List[np.ndarray]] = {}
prng = value.parse_random_state(seed)
for i in range(repetitions):
op = ops.measure(*qubits, key=str(i))
state = self.state.copy()
ch_form_args = ActOnStabilizerCHFormArgs(state, prng, measurements, self.qubits)
protocols.act_on(op, ch_form_args)
return np.array(list(measurements.values()), dtype=bool)


def _strat_act_on_stabilizer_ch_form_from_single_qubit_decompose(
val: Any, args: 'cirq.ActOnStabilizerCHFormArgs', qubits: Sequence['cirq.Qid']
Expand Down