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

Add classical simulator #6124

Merged
merged 125 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
87dc8f4
added the basic first version of the classical simulator to my branch
naerabati Apr 2, 2023
1b7ab94
added formatting
naerabati Apr 3, 2023
28a1049
edited the qubit order and tests
naerabati Apr 4, 2023
21efeaa
added more test cases
naerabati Apr 4, 2023
152e054
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Apr 4, 2023
fa1102c
fixed some error in the test file
naerabati Apr 4, 2023
9795119
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Apr 9, 2023
041c293
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Apr 10, 2023
7cf6b87
added param_resolver and test cases
naerabati Apr 10, 2023
8bff310
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati May 12, 2023
df7bfcc
changed mutliple_instances test
naerabati May 12, 2023
da44625
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati May 12, 2023
9559af9
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jun 7, 2023
2f3d765
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Jun 7, 2023
36fcce5
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jun 13, 2023
3b7bc89
updated comments
naerabati Jun 13, 2023
95800f3
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Jun 13, 2023
690ef69
updated inputs
naerabati Jun 13, 2023
867f6cf
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jun 13, 2023
9f9c760
formatted files
naerabati Jun 14, 2023
154dc72
deleted vs files
naerabati Jun 14, 2023
1f3f321
changed comments
naerabati Jun 14, 2023
3d700e6
updated commenst
naerabati Jun 14, 2023
16738e9
changed the import statements
naerabati Jun 19, 2023
7466c3c
updated imports
naerabati Jun 19, 2023
bab3b0b
changed comments
naerabati Jun 19, 2023
e4b1f58
changed spacing
naerabati Jun 19, 2023
5146a44
updated spacing
naerabati Jun 19, 2023
1d7744f
changed comments
naerabati Jun 21, 2023
0a486b2
updated self argument
naerabati Jun 21, 2023
a5723eb
changed imports
naerabati Jun 21, 2023
f2f2c60
changed imports
naerabati Jun 21, 2023
30855ee
changed imports
naerabati Jun 21, 2023
a8bc3c5
updated imports
naerabati Jun 21, 2023
ded44ed
updated imports
naerabati Jun 21, 2023
01aa246
updated spacing
naerabati Jun 21, 2023
15924e7
changed arguments
naerabati Jun 21, 2023
12e0571
changed arguments
naerabati Jun 21, 2023
68c85ff
updated arguments
naerabati Jun 21, 2023
886944f
updated arguments
naerabati Jun 21, 2023
a368eac
updated files
naerabati Jun 21, 2023
4f069a8
updated file
naerabati Jun 21, 2023
53d918e
changed format
naerabati Jun 21, 2023
9546e79
added self
naerabati Jun 21, 2023
5cf16bb
formatted
naerabati Jun 21, 2023
d30d536
added swap
naerabati Jun 26, 2023
62aabfd
added swap
naerabati Jun 26, 2023
60a0ce1
added swap test
naerabati Jun 26, 2023
c87689c
added CCNOT gate
naerabati Jun 28, 2023
669d33c
formatted
naerabati Jun 28, 2023
3338e7c
updated test case for CCNOT
naerabati Jun 29, 2023
be30e5e
merge changes from master into add_classical simulator
naerabati Jul 5, 2023
686c502
reverted files
naerabati Jul 5, 2023
b2f7835
reverted files
naerabati Jul 5, 2023
61e4c98
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jul 5, 2023
7710ef2
reverted files
naerabati Jul 7, 2023
8814187
added to should not be serialized
naerabati Jul 7, 2023
7d1677d
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Jul 7, 2023
962b8b2
changed syntax
naerabati Jul 7, 2023
d7c4d3c
reformatted
naerabati Jul 7, 2023
7c68107
updated test
naerabati Jul 7, 2023
7d29f8b
formatted
naerabati Jul 7, 2023
baeeee0
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jul 7, 2023
ef4831a
updated format
naerabati Jul 7, 2023
1f9de2c
changed format
naerabati Jul 7, 2023
f54d232
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jul 11, 2023
8fa47d0
fixed long lines
naerabati Jul 11, 2023
866bc4e
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Jul 11, 2023
fc85691
merged with master
naerabati Jul 11, 2023
07962bb
reformatted
naerabati Jul 11, 2023
be240e8
updated comments
naerabati Jul 11, 2023
3403f9a
reformatted
naerabati Jul 12, 2023
6b64f7b
updated imports
naerabati Jul 12, 2023
3c8798c
Merge branch 'master' into add_classical_simulator
naerabati Jul 13, 2023
c9b7741
Merge branch 'master' into add_classical_simulator
naerabati Jul 19, 2023
7dc9213
Merge branch 'master' into add_classical_simulator
naerabati Jul 20, 2023
136e3c0
Merge branch 'master' into add_classical_simulator
naerabati Jul 26, 2023
20bb30e
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Jul 27, 2023
2d436f6
Merge branch 'master' into add_classical_simulator
naerabati Aug 2, 2023
57d0770
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Aug 14, 2023
5b522f6
Merge branch 'master' into add_classical_simulator
naerabati Aug 16, 2023
eac993e
Merge branch 'master' into add_classical_simulator
naerabati Aug 19, 2023
90f9855
restored file
naerabati Aug 19, 2023
36d4391
Merge branch 'master' into add_classical_simulator
naerabati Aug 28, 2023
f284513
changed tests to sim.run function
naerabati Aug 28, 2023
732234e
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Aug 28, 2023
97946c6
removed, checking for gate exponenets of 0
naerabati Aug 28, 2023
9f08a2d
formatted
naerabati Aug 28, 2023
dbb83d7
reverted back to _run
naerabati Aug 28, 2023
2d8b903
reverted unitary_protocol_test to master
naerabati Aug 28, 2023
0edea6c
formatted
naerabati Aug 28, 2023
ba426f8
changed parameter name
naerabati Aug 28, 2023
eccf29b
forma
naerabati Aug 29, 2023
89a52ae
formatted
naerabati Aug 29, 2023
464dd53
updated test
naerabati Aug 29, 2023
e32cdb2
Merge branch 'master' into add_classical_simulator
naerabati Aug 30, 2023
ad62928
fixed line too long
naerabati Sep 20, 2023
0a72999
Merge branch 'add_classical_simulator' of https://github.com/naerabat…
naerabati Sep 20, 2023
1ef4f52
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Sep 20, 2023
1b612f1
moved parenthesis
naerabati Sep 20, 2023
b22c47e
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Oct 4, 2023
77c6430
added test records
naerabati Oct 4, 2023
11f7803
test dictionary
naerabati Oct 4, 2023
2ca4c11
changed argument
naerabati Oct 4, 2023
de7d1c4
changed format
naerabati Oct 4, 2023
e32a046
fixed format
naerabati Oct 4, 2023
4cdd45d
changed measurements
naerabati Oct 4, 2023
399ff68
test dictionary
naerabati Oct 4, 2023
6477270
update dictionary
naerabati Oct 4, 2023
ed0ae54
test dictionary
naerabati Oct 4, 2023
749200e
updated records
naerabati Oct 4, 2023
a62de00
changed circuit parameters
naerabati Oct 8, 2023
0b258a2
updated circuit parameter
naerabati Oct 9, 2023
21a7f9d
updated test_unknown_gate value
naerabati Oct 12, 2023
2c7e003
updated line indent
naerabati Oct 13, 2023
6168c75
Merge branch 'quantumlib:master' into add_classical_simulator
naerabati Nov 8, 2023
93d16f7
restore unrelated files to their original state
naerabati Nov 13, 2023
c09aeca
restore unrelated files to their original state
naerabati Nov 13, 2023
d479fb2
added _ = for test case unassigned line
naerabati Nov 13, 2023
2b9c078
restored files
naerabati Nov 13, 2023
c3b557e
Merge branch 'master' into add_classical_simulator
NoureldinYosri Nov 13, 2023
9e6c138
remove .vs files
NoureldinYosri Nov 13, 2023
41bb80e
restore unrelated files to their original state
NoureldinYosri Nov 13, 2023
3bc22cf
fix style
NoureldinYosri Nov 13, 2023
c8cd782
Merge branch 'master' into add_classical_simulator
NoureldinYosri Nov 13, 2023
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ docs/api_docs

# notebook test output
out

#ignore vs files
.vs/*
1 change: 1 addition & 0 deletions cirq-core/cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@

from cirq.sim import (
CIRCUIT_LIKE,
ClassicalStateSimulator,
CliffordSimulator,
CliffordState,
CliffordSimulatorStepResult,
Expand Down
1 change: 1 addition & 0 deletions cirq-core/cirq/protocols/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
'ZerosSampler',
],
should_not_be_serialized=[
'ClassicalStateSimulator',
# Heatmaps
'Heatmap',
'TwoQubitInteractionHeatmap',
Expand Down
2 changes: 0 additions & 2 deletions cirq-core/cirq/protocols/unitary_protocol_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ def _test_gate_that_allocates_qubits(gate):
def test_decompose_gate_that_allocates_clean_qubits(
theta: float, phase_state: int, target_bitsize: int, ancilla_bitsize: int
):

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this file please, since these whitespace changes are not relevant to the PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, please revert

gate = testing.PhaseUsingCleanAncilla(theta, phase_state, target_bitsize, ancilla_bitsize)
_test_gate_that_allocates_qubits(gate)

Expand All @@ -220,7 +219,6 @@ def test_decompose_gate_that_allocates_clean_qubits(
def test_decompose_gate_that_allocates_dirty_qubits(
phase_state: int, target_bitsize: int, ancilla_bitsize: int
):

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, please revert the unrelated changes.

gate = testing.PhaseUsingDirtyAncilla(phase_state, target_bitsize, ancilla_bitsize)
_test_gate_that_allocates_qubits(gate)

Expand Down
2 changes: 2 additions & 0 deletions cirq-core/cirq/sim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@

from cirq.sim.state_vector_simulation_state import StateVectorSimulationState

from cirq.sim.classical_simulator import ClassicalStateSimulator

from cirq.sim.state_vector_simulator import (
SimulatesIntermediateStateVector,
StateVectorStepResult,
Expand Down
110 changes: 110 additions & 0 deletions cirq-core/cirq/sim/classical_simulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright 2023 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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 Dict
from collections import defaultdict
from cirq.sim.simulator import SimulatesSamples
from cirq import ops, protocols
from cirq.study.resolver import ParamResolver
from cirq.circuits.circuit import AbstractCircuit
from cirq.ops.raw_types import Qid
import numpy as np


class ClassicalStateSimulator(SimulatesSamples):
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
"""basic simulator that only accepts cirq.X, cirq.ISwap, and cirq.CNOT gates
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please replace the docstring with

    """A simulator that only accepts only gates with classical counterparts.

    This simulator evolves a single state, using only gates that output a single state for each
    input state. The simulator runs in linear time, at the cost of not supporting superposition.
    It can be used to estimate costs and simulate circuits for simple non-quantum algorithms using
    many more qubits than fully capable quantum simulators.

    The supported gates are:
        - cirq.X
        - cirq.CNOT
        - cirq.SWAP
        - cirq.TOFFOLI
        - cirq.measure

    Args:
        circuit: The circuit to simulate.
        param_resolver: Parameters to run with the program.
        repetitions: Number of times to repeat the run. It is expected that
            this is validated greater than zero before calling this method.

    Returns:
        A dictionary mapping measurement keys to measurement results.

    Raises:
        ValueError: If one of the gates is not an X, CNOT, SWAP, TOFFOLI or a measurement.
    """


Run a simulation, mimicking quantum hardware.
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved

Args:
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
circuit: The circuit to simulate.
param_resolver: Parameters to run with the program.
repetitions: Number of times to repeat the run. It is expected that
this is validated greater than zero before calling this method.

Returns:
A dictionary from measurement gate key to measurement
results. Measurement results are stored in a 3-dimensional
numpy array, the first dimension corresponding to the repetition.
the second to the instance of that key in the circuit, and the
third to the actual boolean measurement results (ordered by the
qubits being measured.)

Raises:
ValuesError: gate is not a cirq.XGate or cirq.Cnot
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
"""

def _run(
self, circuit: AbstractCircuit, param_resolver: ParamResolver, repetitions: int
) -> Dict[str, np.ndarray]:
results_dict: Dict[str, np.ndarray] = {}
values_dict: Dict[Qid, int] = defaultdict(int)
param_resolver = param_resolver or ParamResolver({})
resolved_circuit = protocols.resolve_parameters(circuit, param_resolver)

for moment in resolved_circuit:
for op in moment:
gate = op.gate
if isinstance(gate, ops.XPowGate) and gate.exponent == 1:
values_dict[op.qubits[0]] = 1 - values_dict[op.qubits[0]]

elif isinstance(gate, ops.CNotPowGate) and gate.exponent == 1:
if values_dict[op.qubits[0]] == 1:
values_dict[op.qubits[1]] = 1 - values_dict[op.qubits[1]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to check for globa_shift == 0 for eigen gates -- let's instead do an equality comparision to ops.X, ops.CX etc. since eventually we'd anyway want to shift to a protocols based approach.


dstrain115 marked this conversation as resolved.
Show resolved Hide resolved
elif isinstance(gate, ops.SwapPowGate) and gate.exponent == 1:
hold_qubit = values_dict[op.qubits[1]]
values_dict[op.qubits[1]] = values_dict[op.qubits[0]]
values_dict[op.qubits[0]] = hold_qubit

elif isinstance(gate, ops.CCXPowGate) and gate.exponent == 1:
if (values_dict[op.qubits[0]] == 1) and (values_dict[op.qubits[1]] == 1):
values_dict[op.qubits[2]] = 1 - values_dict[op.qubits[2]]

elif isinstance(gate, ops.MeasurementGate):
qubits_in_order = op.qubits
##add the new instance of a key to the numpy array in results dictionary
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
##add the new instance of a key to the numpy array in results dictionary
# add the new instance of a key to the numpy array in results dictionary

if (gate.key) in results_dict.keys():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (gate.key) in results_dict.keys():
if gate.key in results_dict:

shape = len(qubits_in_order)
current_array = results_dict[gate.key]
new_instance = np.zeros(shape, dtype=np.uint8)
for bits in range(0, len(qubits_in_order)):
new_instance[bits] = values_dict[qubits_in_order[bits]]
results_dict[gate.key] = np.insert(
current_array, len(current_array[0]), new_instance, axis=1
)
else:
##create the array for the results dictionary
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
##create the array for the results dictionary
# create the array for the results dictionary

new_array_shape = (repetitions, 1, len(qubits_in_order))
new_array = np.zeros(new_array_shape, dtype=np.uint8)
for reps in range(0, repetitions):
for instances in range(0, 1):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

range(0, 1) will just iterate over 0 - use the constant instead of the loop.

for bits in range(0, len(qubits_in_order)):
new_array[reps][instances][bits] = values_dict[
qubits_in_order[bits]
]
results_dict[gate.key] = new_array

elif not (
(isinstance(gate, ops.XPowGate) and gate.exponent == 0)
or (isinstance(gate, ops.CCXPowGate) and gate.exponent == 0)
or (isinstance(gate, ops.SwapPowGate) and gate.exponent == 0)
or (isinstance(gate, ops.CNotPowGate) and gate.exponent == 0)
):
raise ValueError(
"Can not simulate gates other than cirq.XGate, "
+ "cirq.CNOT, cirq.SWAP, and cirq.CCNOT"
)

return results_dict
196 changes: 196 additions & 0 deletions cirq-core/cirq/sim/classical_simulator_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Copyright 2023 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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 numpy as np
import pytest
import cirq
import sympy


class TestSimulator:
NoureldinYosri marked this conversation as resolved.
Show resolved Hide resolved
def test_x_gate(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.X(q1))
circuit.append(cirq.X(q1))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_CNOT(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.measure(q1, key='key'))
expected_results = {'key': np.array([[[1]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sim._run is a private method. Please write the tests using the public method sim.run

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the function is a response to the _run function in the SimulatesStates class it wont's work correctly using the public run method

np.testing.assert_equal(results, expected_results)

def test_Swap(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.SWAP(q0, q1))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[0, 1]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_CCNOT(self):
q0, q1, q2 = cirq.LineQubit.range(3)
circuit = cirq.Circuit()
circuit.append(cirq.CCNOT(q0, q1, q2))
circuit.append(cirq.measure((q0, q1, q2), key='key'))
circuit.append(cirq.X(q0))
circuit.append(cirq.CCNOT(q0, q1, q2))
circuit.append(cirq.measure((q0, q1, q2), key='key'))
circuit.append(cirq.X(q1))
circuit.append(cirq.X(q0))
circuit.append(cirq.CCNOT(q0, q1, q2))
circuit.append(cirq.measure((q0, q1, q2), key='key'))
circuit.append(cirq.X(q0))
circuit.append(cirq.CCNOT(q0, q1, q2))
circuit.append(cirq.measure((q0, q1, q2), key='key'))
expected_results = {
'key': np.array([[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 1]]], dtype=np.uint8)
}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_measurement_gate(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[0, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_qubit_order(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.X(q0))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_same_key_instances(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.measure((q0, q1), key='key'))
circuit.append(cirq.X(q0))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[0, 0], [1, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_same_key_instances_order(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.measure((q0, q1), key='key'))
circuit.append(cirq.X(q0))
circuit.append(cirq.measure((q1, q0), key='key'))
expected_results = {'key': np.array([[[1, 0], [0, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_repetitions(self):
q0 = cirq.LineQubit.range(1)
circuit = cirq.Circuit()
circuit.append(cirq.measure(q0, key='key'))
expected_results = {
'key': np.array(
[[[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]]],
dtype=np.uint8,
)
}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=10)
np.testing.assert_equal(results, expected_results)

def test_multiple_gates(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.X(q1))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_multiple_gates_order(self):
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(cirq.CNOT(q0, q1))
circuit.append(cirq.CNOT(q1, q0))
circuit.append(cirq.measure((q0, q1), key='key'))
expected_results = {'key': np.array([[[0, 1]]], dtype=np.uint8)}
sim = cirq.ClassicalStateSimulator()
results = sim._run(circuit=circuit, param_resolver=None, repetitions=1)
np.testing.assert_equal(results, expected_results)

def test_param_resolver(self):
gate = cirq.CNOT ** sympy.Symbol('t')
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(cirq.X(q0))
circuit.append(gate(q0, q1))
circuit.append(cirq.measure((q1), key='key'))
resolver = cirq.ParamResolver({'t': 0})
sim = cirq.ClassicalStateSimulator()
results_with_paramter_zero = sim._run(
circuit=circuit, param_resolver=resolver, repetitions=1
)
resolver = cirq.ParamResolver({'t': 1})
results_with_paramter_one = sim._run(
circuit=circuit, param_resolver=resolver, repetitions=1
)
np.testing.assert_equal(
results_with_paramter_zero, {'key': np.array([[[0]]], dtype=np.uint8)}
)
np.testing.assert_equal(
results_with_paramter_one, {'key': np.array([[[1]]], dtype=np.uint8)}
)

def test_unknown_gates(self):
gate = cirq.CNOT ** sympy.Symbol('t')
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
circuit.append(gate(q0, q1))
circuit.append(cirq.measure((q0), key='key'))
resolver = cirq.ParamResolver({'t': 0.5})
sim = cirq.ClassicalStateSimulator()
with pytest.raises(
ValueError,
match="Can not simulate gates other than "
+ "cirq.XGate, cirq.CNOT, cirq.SWAP, and cirq.CCNOT",
):
sim._run(circuit=circuit, param_resolver=resolver, repetitions=1)