22
22
import numpy as np
23
23
24
24
25
+ def _is_identity (op : ops .Operation ) -> bool :
26
+ if isinstance (op .gate , (ops .XPowGate , ops .CXPowGate , ops .CCXPowGate , ops .SwapPowGate )):
27
+ return op .gate .exponent % 2 == 0
28
+ return False
29
+
30
+
25
31
class ClassicalStateSimulator (SimulatesSamples ):
26
- """A simulator that only accepts only gates with classical counterparts.
32
+ """A simulator that accepts only gates with classical counterparts.
27
33
28
34
This simulator evolves a single state, using only gates that output a single state for each
29
35
input state. The simulator runs in linear time, at the cost of not supporting superposition.
@@ -47,7 +53,9 @@ class ClassicalStateSimulator(SimulatesSamples):
47
53
A dictionary mapping measurement keys to measurement results.
48
54
49
55
Raises:
50
- ValueError: If one of the gates is not an X, CNOT, SWAP, TOFFOLI or a measurement.
56
+ ValueError: If
57
+ - one of the gates is not an X, CNOT, SWAP, TOFFOLI or a measurement.
58
+ - A measurement key is used for measurements on different numbers of qubits.
51
59
"""
52
60
53
61
def _run (
@@ -60,68 +68,40 @@ def _run(
60
68
61
69
for moment in resolved_circuit :
62
70
for op in moment :
63
- gate = op .gate
64
- if gate == ops .X :
65
- values_dict [op .qubits [0 ]] = 1 - values_dict [op .qubits [0 ]]
66
-
67
- elif (
68
- isinstance (gate , ops .CNotPowGate )
69
- and gate .exponent == 1
70
- and gate .global_shift == 0
71
- ):
72
- if values_dict [op .qubits [0 ]] == 1 :
73
- values_dict [op .qubits [1 ]] = 1 - values_dict [op .qubits [1 ]]
74
-
75
- elif (
76
- isinstance (gate , ops .SwapPowGate )
77
- and gate .exponent == 1
78
- and gate .global_shift == 0
79
- ):
80
- hold_qubit = values_dict [op .qubits [1 ]]
81
- values_dict [op .qubits [1 ]] = values_dict [op .qubits [0 ]]
82
- values_dict [op .qubits [0 ]] = hold_qubit
83
-
84
- elif (
85
- isinstance (gate , ops .CCXPowGate )
86
- and gate .exponent == 1
87
- and gate .global_shift == 0
88
- ):
89
- if (values_dict [op .qubits [0 ]] == 1 ) and (values_dict [op .qubits [1 ]] == 1 ):
90
- values_dict [op .qubits [2 ]] = 1 - values_dict [op .qubits [2 ]]
91
-
92
- elif isinstance (gate , ops .MeasurementGate ):
93
- qubits_in_order = op .qubits
94
- # add the new instance of a key to the numpy array in results dictionary
95
- if gate .key in results_dict :
96
- shape = len (qubits_in_order )
97
- current_array = results_dict [gate .key ]
98
- new_instance = np .zeros (shape , dtype = np .uint8 )
99
- for bits in range (0 , len (qubits_in_order )):
100
- new_instance [bits ] = values_dict [qubits_in_order [bits ]]
101
- results_dict [gate .key ] = np .insert (
102
- current_array , len (current_array [0 ]), new_instance , axis = 1
71
+ if _is_identity (op ):
72
+ continue
73
+ if op .gate == ops .X :
74
+ (q ,) = op .qubits
75
+ values_dict [q ] ^= 1
76
+ elif op .gate == ops .CNOT :
77
+ c , q = op .qubits
78
+ values_dict [q ] ^= values_dict [c ]
79
+ elif op .gate == ops .SWAP :
80
+ a , b = op .qubits
81
+ values_dict [a ], values_dict [b ] = values_dict [b ], values_dict [a ]
82
+ elif op .gate == ops .TOFFOLI :
83
+ c1 , c2 , q = op .qubits
84
+ values_dict [q ] ^= values_dict [c1 ] & values_dict [c2 ]
85
+ elif protocols .is_measurement (op ):
86
+ measurement_values = np .array (
87
+ [[[values_dict [q ] for q in op .qubits ]]] * repetitions , dtype = np .uint8
88
+ )
89
+ key = op .gate .key # type: ignore
90
+ if key in results_dict :
91
+ if op ._num_qubits_ () != results_dict [key ].shape [- 1 ]:
92
+ raise ValueError (
93
+ f'Measurement shape { len (measurement_values )} does not match '
94
+ f'{ results_dict [key ].shape [- 1 ]} in { key } .'
103
95
)
96
+ results_dict [key ] = np .concatenate (
97
+ (results_dict [key ], measurement_values ), axis = 1
98
+ )
104
99
else :
105
- # create the array for the results dictionary
106
- new_array_shape = (repetitions , 1 , len (qubits_in_order ))
107
- new_array = np .zeros (new_array_shape , dtype = np .uint8 )
108
- for reps in range (0 , repetitions ):
109
- for instances in range (1 ):
110
- for bits in range (0 , len (qubits_in_order )):
111
- new_array [reps ][instances ][bits ] = values_dict [
112
- qubits_in_order [bits ]
113
- ]
114
- results_dict [gate .key ] = new_array
115
-
116
- elif not (
117
- (isinstance (gate , ops .XPowGate ) and gate .exponent == 0 )
118
- or (isinstance (gate , ops .CCXPowGate ) and gate .exponent == 0 )
119
- or (isinstance (gate , ops .SwapPowGate ) and gate .exponent == 0 )
120
- or (isinstance (gate , ops .CNotPowGate ) and gate .exponent == 0 )
121
- ):
100
+ results_dict [key ] = measurement_values
101
+ else :
122
102
raise ValueError (
123
- "Can not simulate gates other than cirq.XGate, "
124
- + " cirq.CNOT, cirq.SWAP, and cirq.CCNOT"
103
+ f' { op } is not one of cirq.X, cirq.CNOT, cirq.SWAP, '
104
+ ' cirq.CCNOT, or a measurement'
125
105
)
126
106
127
107
return results_dict
0 commit comments