1010// or implied. See the License for the specific language governing permissions and limitations under
1111// the License.
1212
13- // use pecos_core::VecSet;
14- // use pecos_qsims::CliffordSimulator;
15- // use pecos_qsims::SparseStab;
1613use pecos:: prelude:: * ;
1714use pyo3:: prelude:: * ;
1815use pyo3:: types:: { PyDict , PyTuple } ;
19- use std:: collections:: HashMap ;
2016
2117#[ pyclass]
2218pub struct SparseSim {
@@ -32,195 +28,117 @@ impl SparseSim {
3228 }
3329 }
3430
31+ fn reset ( & mut self ) {
32+ self . inner . reset ( ) ;
33+ }
34+
3535 #[ allow( clippy:: too_many_lines) ]
3636 #[ pyo3( signature = ( symbol, location, params=None ) ) ]
37- fn run_gate (
37+ fn run_1q_gate (
3838 & mut self ,
3939 symbol : & str ,
40- location : & Bound < ' _ , PyTuple > ,
40+ location : usize ,
4141 params : Option < & Bound < ' _ , PyDict > > ,
42- ) -> PyResult < Option < HashMap < usize , u8 > > > {
43- match ( symbol, location. len ( ) ) {
44- ( "X" , 1 ) => {
45- self . inner . x ( location. get_item ( 0 ) ?. extract ( ) ?) ;
46- Ok ( None )
47- }
48- ( "Y" , 1 ) => {
49- self . inner . y ( location. get_item ( 0 ) ?. extract ( ) ?) ;
50- Ok ( None )
51- }
52- ( "Z" , 1 ) => {
53- self . inner . z ( location. get_item ( 0 ) ?. extract ( ) ?) ;
54- Ok ( None )
55- }
56- ( "H" , 1 ) => {
57- self . inner . h ( location. get_item ( 0 ) ?. extract ( ) ?) ;
42+ ) -> PyResult < Option < u8 > > {
43+ match symbol {
44+ "X" => {
45+ self . inner . x ( location) ;
5846 Ok ( None )
5947 }
60- ( "H2" , 1 ) => {
61- self . inner . h2 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
48+ "Y" => {
49+ self . inner . y ( location) ;
6250 Ok ( None )
6351 }
64- ( "H3" , 1 ) => {
65- self . inner . h3 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
52+ "Z" => {
53+ self . inner . z ( location) ;
6654 Ok ( None )
6755 }
68- ( "H4" , 1 ) => {
69- self . inner . h4 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
56+ "H" => {
57+ self . inner . h ( location) ;
7058 Ok ( None )
7159 }
72- ( "H5" , 1 ) => {
73- self . inner . h5 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
60+ "H2" => {
61+ self . inner . h2 ( location) ;
7462 Ok ( None )
7563 }
76- ( "H6" , 1 ) => {
77- self . inner . h6 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
64+ "H3" => {
65+ self . inner . h3 ( location) ;
7866 Ok ( None )
7967 }
80- ( "F" , 1 ) => {
81- self . inner . f ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
68+ "H4" => {
69+ self . inner . h4 ( location) ;
8270 Ok ( None )
8371 }
84- ( "Fdg" , 1 ) => {
85- self . inner . fdg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
72+ "H5" => {
73+ self . inner . h5 ( location) ;
8674 Ok ( None )
8775 }
88- ( "F2" , 1 ) => {
89- self . inner . f2 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
76+ "H6" => {
77+ self . inner . h6 ( location) ;
9078 Ok ( None )
9179 }
92- ( "F2dg" , 1 ) => {
93- self . inner . f2dg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
80+ "F" => {
81+ self . inner . f ( location) ;
9482 Ok ( None )
9583 }
96- ( "F3" , 1 ) => {
97- self . inner . f3 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
84+ "Fdg" => {
85+ self . inner . fdg ( location) ;
9886 Ok ( None )
9987 }
100- ( "F3dg" , 1 ) => {
101- self . inner . f3dg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
88+ "F2" => {
89+ self . inner . f2 ( location) ;
10290 Ok ( None )
10391 }
104- ( "F4" , 1 ) => {
105- self . inner . f4 ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
92+ "F2dg" => {
93+ self . inner . f2dg ( location) ;
10694 Ok ( None )
10795 }
108- ( "F4dg" , 1 ) => {
109- self . inner . f4dg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
96+ "F3" => {
97+ self . inner . f3 ( location) ;
11098 Ok ( None )
11199 }
112- ( "SX" , 1 ) => {
113- self . inner . sx ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
100+ "F3dg" => {
101+ self . inner . f3dg ( location) ;
114102 Ok ( None )
115103 }
116- ( "SXdg" , 1 ) => {
117- self . inner . sxdg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
104+ "F4" => {
105+ self . inner . f4 ( location) ;
118106 Ok ( None )
119107 }
120- ( "SY" , 1 ) => {
121- self . inner . sy ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
108+ "F4dg" => {
109+ self . inner . f4dg ( location) ;
122110 Ok ( None )
123111 }
124- ( "SYdg" , 1 ) => {
125- self . inner . sydg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
112+ "SX" => {
113+ self . inner . sx ( location) ;
126114 Ok ( None )
127115 }
128- ( "SZ" , 1 ) => {
129- self . inner . sz ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
116+ "SXdg" => {
117+ self . inner . sxdg ( location) ;
130118 Ok ( None )
131119 }
132- ( "SZdg" , 1 ) => {
133- self . inner . szdg ( location. get_item ( 0 ) ? . extract ( ) ? ) ;
120+ "SY" => {
121+ self . inner . sy ( location) ;
134122 Ok ( None )
135123 }
136- ( "CX" , 2 ) => {
137- self . inner . cx (
138- location. get_item ( 0 ) ?. extract ( ) ?,
139- location. get_item ( 1 ) ?. extract ( ) ?,
140- ) ;
124+ "SYdg" => {
125+ self . inner . sydg ( location) ;
141126 Ok ( None )
142127 }
143- ( "CY" , 2 ) => {
144- self . inner . cy (
145- location. get_item ( 0 ) ?. extract ( ) ?,
146- location. get_item ( 1 ) ?. extract ( ) ?,
147- ) ;
128+ "SZ" => {
129+ self . inner . sz ( location) ;
148130 Ok ( None )
149131 }
150- ( "CZ" , 2 ) => {
151- self . inner . cz (
152- location. get_item ( 0 ) ?. extract ( ) ?,
153- location. get_item ( 1 ) ?. extract ( ) ?,
154- ) ;
132+ "SZdg" => {
133+ self . inner . szdg ( location) ;
155134 Ok ( None )
156135 }
157- ( "SXX" , 2 ) => {
158- self . inner . sxx (
159- location. get_item ( 0 ) ?. extract ( ) ?,
160- location. get_item ( 1 ) ?. extract ( ) ?,
161- ) ;
162- Ok ( None )
163- }
164- ( "SXXdg" , 2 ) => {
165- self . inner . sxxdg (
166- location. get_item ( 0 ) ?. extract ( ) ?,
167- location. get_item ( 1 ) ?. extract ( ) ?,
168- ) ;
169- Ok ( None )
170- }
171- ( "SYY" , 2 ) => {
172- self . inner . syy (
173- location. get_item ( 0 ) ?. extract ( ) ?,
174- location. get_item ( 1 ) ?. extract ( ) ?,
175- ) ;
176- Ok ( None )
177- }
178- ( "SYYdg" , 2 ) => {
179- self . inner . syydg (
180- location. get_item ( 0 ) ?. extract ( ) ?,
181- location. get_item ( 1 ) ?. extract ( ) ?,
182- ) ;
183- Ok ( None )
184- }
185- ( "SZZ" , 2 ) => {
186- self . inner . szz (
187- location. get_item ( 0 ) ?. extract ( ) ?,
188- location. get_item ( 1 ) ?. extract ( ) ?,
189- ) ;
190- Ok ( None )
191- }
192- ( "SZZdg" , 2 ) => {
193- self . inner . szzdg (
194- location. get_item ( 0 ) ?. extract ( ) ?,
195- location. get_item ( 1 ) ?. extract ( ) ?,
196- ) ;
197- Ok ( None )
198- }
199- ( "SWAP" , 2 ) => {
200- self . inner . swap (
201- location. get_item ( 0 ) ?. extract ( ) ?,
202- location. get_item ( 1 ) ?. extract ( ) ?,
203- ) ;
204- Ok ( None )
205- }
206-
207- ( "G2" , 2 ) => {
208- self . inner . g2 (
209- location. get_item ( 0 ) ?. extract ( ) ?,
210- location. get_item ( 1 ) ?. extract ( ) ?,
211- ) ;
212- Ok ( None )
213- }
214- (
215- "MZ" | "MX" | "MY" | "MZForced" | "PZ" | "PX" | "PY" | "PZForced" | "PnZ" | "PnX"
216- | "PnY" ,
217- 1 ,
218- ) => {
219- let qubit: usize = location. get_item ( 0 ) ?. extract ( ) ?;
136+ "MZ" | "MX" | "MY" | "MZForced" | "PZ" | "PX" | "PY" | "PZForced" | "PnZ" | "PnX"
137+ | "PnY" => {
220138 let ( result, _) = match symbol {
221- "MZ" => self . inner . mz ( qubit ) ,
222- "MX" => self . inner . mx ( qubit ) ,
223- "MY" => self . inner . my ( qubit ) ,
139+ "MZ" => self . inner . mz ( location ) ,
140+ "MX" => self . inner . mx ( location ) ,
141+ "MY" => self . inner . my ( location ) ,
224142 "MZForced" => {
225143 let forced_value = params
226144 . ok_or_else ( || {
@@ -236,11 +154,11 @@ impl SparseSim {
236154 } ) ?
237155 . call_method0 ( "__bool__" ) ?
238156 . extract :: < bool > ( ) ?;
239- self . inner . mz_forced ( qubit , forced_value)
157+ self . inner . mz_forced ( location , forced_value)
240158 }
241- "PZ" => self . inner . pz ( qubit ) ,
242- "PX" => self . inner . px ( qubit ) ,
243- "PY" => self . inner . py ( qubit ) ,
159+ "PZ" => self . inner . pz ( location ) ,
160+ "PX" => self . inner . px ( location ) ,
161+ "PY" => self . inner . py ( location ) ,
244162 "PZForced" => {
245163 let forced_value = params
246164 . ok_or_else ( || {
@@ -256,21 +174,103 @@ impl SparseSim {
256174 } ) ?
257175 . call_method0 ( "__bool__" ) ?
258176 . extract :: < bool > ( ) ?;
259- self . inner . pz_forced ( qubit , forced_value)
177+ self . inner . pz_forced ( location , forced_value)
260178 }
261- "PnZ" => self . inner . pnz ( qubit ) ,
262- "PnX" => self . inner . pnx ( qubit ) ,
263- "PnY" => self . inner . pny ( qubit ) ,
179+ "PnZ" => self . inner . pnz ( location ) ,
180+ "PnX" => self . inner . pnx ( location ) ,
181+ "PnY" => self . inner . pny ( location ) ,
264182 _ => unreachable ! ( ) ,
265183 } ;
266- let mut map = HashMap :: new ( ) ;
267- if result {
268- map. insert ( qubit, 1 ) ;
269- }
270- Ok ( Some ( map) )
184+ Ok ( Some ( u8:: from ( result) ) )
185+ }
186+ _ => Err ( PyErr :: new :: < pyo3:: exceptions:: PyValueError , _ > (
187+ "Unsupported single-qubit gate" ,
188+ ) ) ,
189+ }
190+ }
191+
192+ #[ pyo3( signature = ( symbol, location, _params) ) ]
193+ fn run_2q_gate (
194+ & mut self ,
195+ symbol : & str ,
196+ location : & Bound < ' _ , PyTuple > ,
197+ _params : Option < & Bound < ' _ , PyDict > > ,
198+ ) -> PyResult < Option < u8 > > {
199+ if location. len ( ) != 2 {
200+ return Err ( PyErr :: new :: < pyo3:: exceptions:: PyValueError , _ > (
201+ "Two-qubit gate requires exactly 2 qubit locations" ,
202+ ) ) ;
203+ }
204+
205+ let q1: usize = location. get_item ( 0 ) ?. extract ( ) ?;
206+ let q2: usize = location. get_item ( 1 ) ?. extract ( ) ?;
207+
208+ match symbol {
209+ "CX" => {
210+ self . inner . cx ( q1, q2) ;
211+ Ok ( None )
212+ }
213+ "CY" => {
214+ self . inner . cy ( q1, q2) ;
215+ Ok ( None )
216+ }
217+ "CZ" => {
218+ self . inner . cz ( q1, q2) ;
219+ Ok ( None )
220+ }
221+ "SXX" => {
222+ self . inner . sxx ( q1, q2) ;
223+ Ok ( None )
224+ }
225+ "SXXdg" => {
226+ self . inner . sxxdg ( q1, q2) ;
227+ Ok ( None )
228+ }
229+ "SYY" => {
230+ self . inner . syy ( q1, q2) ;
231+ Ok ( None )
232+ }
233+ "SYYdg" => {
234+ self . inner . syydg ( q1, q2) ;
235+ Ok ( None )
236+ }
237+ "SZZ" => {
238+ self . inner . szz ( q1, q2) ;
239+ Ok ( None )
240+ }
241+ "SZZdg" => {
242+ self . inner . szzdg ( q1, q2) ;
243+ Ok ( None )
244+ }
245+ "SWAP" => {
246+ self . inner . swap ( q1, q2) ;
247+ Ok ( None )
248+ }
249+ "G2" => {
250+ self . inner . g2 ( q1, q2) ;
251+ Ok ( None )
252+ }
253+ _ => Err ( PyErr :: new :: < pyo3:: exceptions:: PyValueError , _ > (
254+ "Unsupported two-qubit gate" ,
255+ ) ) ,
256+ }
257+ }
258+
259+ #[ pyo3( signature = ( symbol, location, params=None ) ) ]
260+ fn run_gate (
261+ & mut self ,
262+ symbol : & str ,
263+ location : & Bound < ' _ , PyTuple > ,
264+ params : Option < & Bound < ' _ , PyDict > > ,
265+ ) -> PyResult < Option < u8 > > {
266+ match location. len ( ) {
267+ 1 => {
268+ let qubit: usize = location. get_item ( 0 ) ?. extract ( ) ?;
269+ self . run_1q_gate ( symbol, qubit, params)
271270 }
271+ 2 => self . run_2q_gate ( symbol, location, params) ,
272272 _ => Err ( PyErr :: new :: < pyo3:: exceptions:: PyValueError , _ > (
273- "Unsupported gate or incorrect number of qubits" ,
273+ "Gate location must be specified for either 1 or 2 qubits" ,
274274 ) ) ,
275275 }
276276 }
0 commit comments