Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
test_gates.py
Go to the documentation of this file.
1 '''
2 Copyright 2020 Peter Rakyta, Ph.D.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see http://www.gnu.org/licenses/.
18 '''
19 
20 import inspect
21 import json
22 import numpy as np
23 import pytest
24 import subprocess
25 import sys
26 
27 from qiskit import QuantumCircuit
28 
29 from squander import Qiskit_IO
30 from squander import utils
31 from squander.gates import gates_Wrapper as gate
32 from squander.gates.qgd_Circuit import qgd_Circuit as Circuit
33 
34 
36  names = []
37  for name in dir(gate):
38  if name.startswith("_"):
39  continue
40  obj = getattr(gate, name)
41  if not inspect.isclass(obj):
42  continue
43  try:
44  if issubclass(obj, gate.Gate):
45  names.append(name)
46  except TypeError:
47  continue
48  return sorted(names)
49 
50 
51 ALL_GATE_NAMES = _discover_gate_names()
52 QISKIT_EXCLUDED_GATES = {"SYC", "CR", "CROT"}
53 QISKIT_MATRIX_UNSUPPORTED = {"Gate"} | QISKIT_EXCLUDED_GATES
54 NATIVE_UNSAFE_MATRIX_GATES = {"Gate"}
55 NATIVE_UNSAFE_APPLY_GATES = {"Gate"}
56 DERIVATIVE_TEST_EXCLUDED_GATES = set()
57 RECT_COLS_MAX = 32
58 F32_TOL = 2e-4
59 
60 
62  names = []
63  for gate_name in ALL_GATE_NAMES:
64  if gate_name in DERIVATIVE_TEST_EXCLUDED_GATES:
65  continue
66  gate_obj = _instantiate_gate(gate_name)
67  if gate_obj.get_Parameter_Num() > 0:
68  names.append(gate_name)
69  return sorted(names)
70 
71 
73  names = []
74  for gate_name in ALL_GATE_NAMES:
75  if gate_name == "Gate":
76  continue
77  gate_obj = _instantiate_gate(gate_name)
78  if len(gate_obj.get_Involved_Qbits()) >= 2:
79  names.append(gate_name)
80  return sorted(names)
81 
82 
83 def _instantiate_gate(gate_name, qbit_num=4):
84  gate_cls = getattr(gate, gate_name)
85 
86  if gate_name == "Gate":
87  return gate_cls(qbit_num)
88  if gate_name in {"SWAP", "RXX", "RYY", "RZZ"}:
89  return gate_cls(qbit_num, [0, qbit_num - 1])
90  if gate_name == "CCX":
91  return gate_cls(qbit_num, 0, [qbit_num - 2, qbit_num - 1])
92  if gate_name == "CSWAP":
93  return gate_cls(qbit_num, [0, 1], [qbit_num - 1])
94  if gate_name == "SYC":
95  return gate_cls(qbit_num, 0, qbit_num - 1)
96  if gate_name.startswith("C"):
97  return gate_cls(qbit_num, 0, qbit_num - 1)
98  return gate_cls(qbit_num, 0)
99 
100 
101 def _parameters_for_gate(gate_obj, dtype=np.float64):
102  pnum = gate_obj.get_Parameter_Num()
103  if pnum == 0:
104  return np.asarray([], dtype=dtype)
105  return np.linspace(0.1, 0.1 * pnum, pnum, dtype=dtype)
106 
107 
108 def _gate_matrix(gate_obj, parameters):
109  if gate_obj.get_Parameter_Num() == 0:
110  return np.asarray(gate_obj.get_Matrix())
111  return np.asarray(gate_obj.get_Matrix(parameters))
112 
113 
114 def _apply_gate(gate_obj, state, parameters, is_f32=False, parallel=0):
115  if gate_obj.get_Parameter_Num() == 0:
116  gate_obj.apply_to(state, parallel=parallel, is_f32=is_f32)
117  else:
118  gate_obj.apply_to(state, parameters=parameters, parallel=parallel, is_f32=is_f32)
119 
120 
121 def _get_matrix_with_precision(gate_obj, parameters, is_f32):
122  if gate_obj.get_Parameter_Num() == 0:
123  return np.asarray(gate_obj.get_Matrix(is_f32=is_f32))
124  return np.asarray(gate_obj.get_Matrix(parameters, is_f32=is_f32))
125 
126 
127 def _apply_to_state_with_precision(gate_obj, state, parameters, is_f32):
128  out = state.copy()
129  if gate_obj.get_Parameter_Num() == 0:
130  gate_obj.apply_to(out, parallel=0, is_f32=is_f32)
131  else:
132  gate_obj.apply_to(out, parameters=parameters, parallel=0, is_f32=is_f32)
133  return out
134 
135 
136 def _apply_to_matrix_with_precision(gate_obj, matrix, parameters, is_f32):
137  out = matrix.copy()
138  if gate_obj.get_Parameter_Num() == 0:
139  gate_obj.apply_to(out, parallel=0, is_f32=is_f32)
140  else:
141  gate_obj.apply_to(out, parameters=parameters, parallel=0, is_f32=is_f32)
142  return out
143 
144 
145 def _apply_from_right_with_precision(gate_obj, matrix, parameters, is_f32):
146  out = matrix.copy()
147  if gate_obj.get_Parameter_Num() == 0:
148  gate_obj.apply_from_right(out, is_f32=is_f32)
149  else:
150  gate_obj.apply_from_right(out, parameters=parameters, is_f32=is_f32)
151  return out
152 
153 
154 def _assert_matrices_close(a, b, tol=1e-8):
155  overlap = np.vdot(a.reshape(-1), b.reshape(-1))
156  if np.abs(overlap) > 0:
157  b = b * np.exp(-1j * np.angle(overlap))
158  err = np.linalg.norm(a - b)
159  assert err < tol, f"matrix mismatch: {err}"
160 
161 
162 def _add_gate_to_qiskit(circuit, gate_name, parameters):
163  target = 0
164  control = circuit.num_qubits - 1
165 
166  qiskit_params = list(parameters)
167  if qiskit_params:
168  if gate_name not in {"U1", "U2", "CP"}:
169  qiskit_params[0] = 2.0 * qiskit_params[0]
170 
171  if gate_name == "U1":
172  circuit.p(*qiskit_params, target)
173  elif gate_name == "U2":
174  circuit.u(np.pi / 2.0, qiskit_params[0], qiskit_params[1], target)
175  elif gate_name == "U3":
176  circuit.u(*qiskit_params, target)
177  elif gate_name == "CNOT":
178  circuit.cx(control, target)
179  elif gate_name == "CU":
180  circuit.cu(
181  qiskit_params[0],
182  qiskit_params[1],
183  qiskit_params[2],
184  qiskit_params[3],
185  control,
186  target,
187  )
188  elif gate_name == "CCX":
189  circuit.ccx(circuit.num_qubits - 2, circuit.num_qubits - 1, target)
190  elif gate_name == "CSWAP":
191  circuit.cswap(circuit.num_qubits - 1, 0, 1)
192  elif gate_name in {"SWAP", "RXX", "RYY", "RZZ"}:
193  method = getattr(circuit, gate_name.lower())
194  if qiskit_params:
195  method(*qiskit_params, 0, circuit.num_qubits - 1)
196  else:
197  method(0, circuit.num_qubits - 1)
198  else:
199  method = getattr(circuit, gate_name.lower())
200  if gate_name.startswith("C"):
201  if qiskit_params:
202  method(*qiskit_params, control, target)
203  else:
204  method(control, target)
205  else:
206  if qiskit_params:
207  method(*qiskit_params, target)
208  else:
209  method(target)
210 
211 
212 MULTI_QUBIT_GATE_NAMES = _discover_multi_qubit_gate_names()
213 DERIVATIVE_GATE_NAMES = _discover_parameterized_gate_names()
214 FORBIDDEN_MULTI_QUBIT_GATES_IN_CNOT_BASIS = {
215  gate_name for gate_name in MULTI_QUBIT_GATE_NAMES if gate_name != "CNOT"
216 }
217 
218 
219 class TestGates:
221  c_circuit = Circuit(3)
222  assert c_circuit.get_Qbit_Num() == 3
223 
225  c_circuit = Circuit(3)
226  c_circuit.add_U3(0)
227  c_circuit.add_CNOT(0, 1)
228 
229  nums = c_circuit.get_Gate_Nums()
230  assert nums.get("U3", 0) == 1
231  assert nums.get("CNOT", 0) == 1
232 
233  @pytest.mark.parametrize("gate_name", ALL_GATE_NAMES)
235  gate_obj = _instantiate_gate(gate_name)
236  base_methods = [
237  name
238  for name, obj in inspect.getmembers(gate.Gate(4))
239  if callable(obj) and not name.startswith("_")
240  ]
241 
242  for method_name in base_methods:
243  assert hasattr(gate_obj, method_name), f"{gate_name} missing method {method_name}"
244 
245  p = _parameters_for_gate(gate_obj)
246  matrix = None
247  if gate_name not in NATIVE_UNSAFE_MATRIX_GATES:
248  matrix = _gate_matrix(gate_obj, p)
249 
250  assert gate_obj.get_Name()
251  assert isinstance(gate_obj.get_Involved_Qbits(), list)
252  assert gate_obj.get_Parameter_Num() >= 0
253  if matrix is not None:
254  assert matrix.shape == (1 << 4, 1 << 4)
255 
256  tgt = gate_obj.get_Target_Qbit()
257  gate_obj.set_Target_Qbit(tgt)
258 
259  tgt_list = list(gate_obj.get_Target_Qbits())
260  if tgt_list:
261  gate_obj.set_Target_Qbits(tgt_list)
262 
263  ctrl_list = list(gate_obj.get_Control_Qbits())
264  if ctrl_list:
265  gate_obj.set_Control_Qbits(ctrl_list)
266  gate_obj.set_Control_Qbit(ctrl_list[0])
267 
268  if gate_name not in NATIVE_UNSAFE_APPLY_GATES and matrix is not None:
269  state = np.random.uniform(-1.0, 1.0, (1 << 4,)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4,))
270  state = state / np.linalg.norm(state)
271  expected = matrix @ state
272  state_out = state.copy()
273 
274  if gate_obj.get_Parameter_Num() == 0:
275  gate_obj.apply_to(state_out)
276  else:
277  gate_obj.apply_to(state_out, p)
278 
279  assert np.linalg.norm(state_out - expected) < 1e-8
280 
281  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
283  script = f"""
284 import json
285 import numpy as np
286 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
287 
288 gate_name = {gate_name!r}
289 
290 try:
291  gate_obj = _instantiate_gate(gate_name)
292  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
293  p32 = p64.astype(np.float32)
294 
295  state64 = np.random.uniform(-1.0, 1.0, (1 << 4,)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4,))
296  state64 = state64.astype(np.complex128)
297  state64 = state64 / np.linalg.norm(state64)
298 
299  state32 = state64.astype(np.complex64)
300  state32 = state32 / np.linalg.norm(state32)
301 
302  out64 = state64.copy()
303  out32 = state32.copy()
304 
305  if gate_obj.get_Parameter_Num() == 0:
306  gate_obj.apply_to(out64, parallel=0, is_f32=False)
307  gate_obj.apply_to(out32, parallel=0, is_f32=True)
308  else:
309  gate_obj.apply_to(out64, parameters=p64, parallel=0, is_f32=False)
310  gate_obj.apply_to(out32, parameters=p32, parallel=0, is_f32=True)
311 
312  err = float(np.linalg.norm(out32 - out64.astype(np.complex64)))
313  print(json.dumps({{"status": "ok", "err": err}}))
314 except Exception as exc:
315  print(json.dumps({{"status": "exception", "message": str(exc)}}))
316 """
317 
318  proc = subprocess.run(
319  [sys.executable, "-c", script],
320  capture_output=True,
321  text=True,
322  check=False,
323  )
324 
325  if proc.returncode != 0:
326  pytest.fail(
327  f"Gate {gate_name} crashed in float32/float64 parity subprocess. "
328  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
329  )
330 
331  result = json.loads(proc.stdout.strip().splitlines()[-1])
332  assert result["status"] == "ok", result
333  assert result["err"] < 1e-4, f"float32/float64 parity mismatch for {gate_name}: {result['err']}"
334 
335  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
337  script = f"""
338 import json
339 import numpy as np
340 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
341 
342 gate_name = {gate_name!r}
343 
344 try:
345  gate_obj = _instantiate_gate(gate_name)
346  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
347  p32 = p64.astype(np.float32)
348 
349  if gate_obj.get_Parameter_Num() == 0:
350  m64 = np.asarray(gate_obj.get_Matrix(is_f32=False))
351  m32 = np.asarray(gate_obj.get_Matrix(is_f32=True))
352  else:
353  m64 = np.asarray(gate_obj.get_Matrix(p64, is_f32=False))
354  m32 = np.asarray(gate_obj.get_Matrix(p32, is_f32=True))
355 
356  err = float(np.linalg.norm(m32 - m64.astype(np.complex64)))
357  print(json.dumps({{"status": "ok", "err": err, "dtype64": str(m64.dtype), "dtype32": str(m32.dtype)}}))
358 except Exception as exc:
359  print(json.dumps({{"status": "exception", "message": str(exc)}}))
360 """
361 
362  proc = subprocess.run(
363  [sys.executable, "-c", script],
364  capture_output=True,
365  text=True,
366  check=False,
367  )
368 
369  if proc.returncode != 0:
370  pytest.fail(
371  f"Gate {gate_name} crashed in get_Matrix float32/float64 parity subprocess. "
372  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
373  )
374 
375  result = json.loads(proc.stdout.strip().splitlines()[-1])
376  assert result["status"] == "ok", result
377  assert result["dtype64"] == "complex128", result
378  assert result["dtype32"] == "complex64", result
379  assert result["err"] < 1e-4, f"float32/float64 get_Matrix parity mismatch for {gate_name}: {result['err']}"
380 
381  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
383  script = f"""
384 import json
385 import numpy as np
386 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
387 
388 gate_name = {gate_name!r}
389 
390 try:
391  gate_obj = _instantiate_gate(gate_name)
392  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
393  p32 = p64.astype(np.float32)
394 
395  inp64 = np.random.uniform(-1.0, 1.0, (1 << 4, 1 << 4)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4, 1 << 4))
396  inp64 = inp64.astype(np.complex128)
397  inp32 = inp64.astype(np.complex64)
398 
399  out64 = inp64.copy()
400  out32 = inp32.copy()
401 
402  if gate_obj.get_Parameter_Num() == 0:
403  gate_obj.apply_from_right(out64, is_f32=False)
404  gate_obj.apply_from_right(out32, is_f32=True)
405  else:
406  gate_obj.apply_from_right(out64, parameters=p64, is_f32=False)
407  gate_obj.apply_from_right(out32, parameters=p32, is_f32=True)
408 
409  err = float(np.linalg.norm(out32 - out64.astype(np.complex64)))
410  print(json.dumps({{"status": "ok", "err": err}}))
411 except Exception as exc:
412  print(json.dumps({{"status": "exception", "message": str(exc)}}))
413 """
414 
415  proc = subprocess.run(
416  [sys.executable, "-c", script],
417  capture_output=True,
418  text=True,
419  check=False,
420  )
421 
422  if proc.returncode != 0:
423  pytest.fail(
424  f"Gate {gate_name} crashed in apply_from_right float32/float64 parity subprocess. "
425  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
426  )
427 
428  result = json.loads(proc.stdout.strip().splitlines()[-1])
429  assert result["status"] == "ok", result
430  assert result["err"] < 1e-4, f"float32/float64 apply_from_right parity mismatch for {gate_name}: {result['err']}"
431 
432  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
434  script = f"""
435 import json
436 import numpy as np
437 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
438 
439 gate_name = {gate_name!r}
440 
441 try:
442  gate_obj = _instantiate_gate(gate_name)
443  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
444  p32 = p64.astype(np.float32)
445 
446  inputs64 = []
447  for _ in range(3):
448  vec = np.random.uniform(-1.0, 1.0, (1 << 4,)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4,))
449  vec = vec.astype(np.complex128)
450  vec = vec / np.linalg.norm(vec)
451  inputs64.append(vec)
452 
453  inputs32 = [v.astype(np.complex64) for v in inputs64]
454 
455  out64 = [v.copy() for v in inputs64]
456  out32 = [v.copy() for v in inputs32]
457 
458  if gate_obj.get_Parameter_Num() == 0:
459  gate_obj.apply_to_list(out64, parallel=0, is_f32=False)
460  gate_obj.apply_to_list(out32, parallel=0, is_f32=True)
461  else:
462  gate_obj.apply_to_list(out64, parameters=p64, parallel=0, is_f32=False)
463  gate_obj.apply_to_list(out32, parameters=p32, parallel=0, is_f32=True)
464 
465  errs = [float(np.linalg.norm(a - b.astype(np.complex64))) for a, b in zip(out32, out64)]
466  print(json.dumps({{"status": "ok", "max_err": float(max(errs))}}))
467 except Exception as exc:
468  print(json.dumps({{"status": "exception", "message": str(exc)}}))
469 """
470 
471  proc = subprocess.run(
472  [sys.executable, "-c", script],
473  capture_output=True,
474  text=True,
475  check=False,
476  )
477 
478  if proc.returncode != 0:
479  pytest.fail(
480  f"Gate {gate_name} crashed in apply_to_list float32/float64 parity subprocess. "
481  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
482  )
483 
484  result = json.loads(proc.stdout.strip().splitlines()[-1])
485  assert result["status"] == "ok", result
486  assert result["max_err"] < 1e-4, f"float32/float64 apply_to_list parity mismatch for {gate_name}: {result['max_err']}"
487 
488  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
490  script = f"""
491 import json
492 import numpy as np
493 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate, RECT_COLS_MAX
494 
495 gate_name = {gate_name!r}
496 
497 try:
498  gate_obj = _instantiate_gate(gate_name)
499  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
500  p32 = p64.astype(np.float32)
501 
502  rng = np.random.default_rng(2026)
503 
504  # apply_to path: 16xN (N=1..32)
505  left64 = np.ascontiguousarray(
506  rng.standard_normal((1 << 4, RECT_COLS_MAX))
507  + 1j * rng.standard_normal((1 << 4, RECT_COLS_MAX)),
508  dtype=np.complex128,
509  )
510  left32 = left64.astype(np.complex64)
511 
512  out_full64 = left64.copy()
513  out_full32 = left32.copy()
514  if gate_obj.get_Parameter_Num() == 0:
515  gate_obj.apply_to(out_full64, parallel=0, is_f32=False)
516  gate_obj.apply_to(out_full32, parallel=0, is_f32=True)
517  else:
518  gate_obj.apply_to(out_full64, parameters=p64, parallel=0, is_f32=False)
519  gate_obj.apply_to(out_full32, parameters=p32, parallel=0, is_f32=True)
520 
521  left_subset_err64 = 0.0
522  left_subset_err32 = 0.0
523  for ncols in range(1, RECT_COLS_MAX + 1):
524  p64_m = np.ascontiguousarray(left64[:, :ncols].copy())
525  p32_m = np.ascontiguousarray(left32[:, :ncols].copy())
526  if gate_obj.get_Parameter_Num() == 0:
527  gate_obj.apply_to(p64_m, parallel=0, is_f32=False)
528  gate_obj.apply_to(p32_m, parallel=0, is_f32=True)
529  else:
530  gate_obj.apply_to(p64_m, parameters=p64, parallel=0, is_f32=False)
531  gate_obj.apply_to(p32_m, parameters=p32, parallel=0, is_f32=True)
532  left_subset_err64 = max(left_subset_err64, float(np.linalg.norm(p64_m - out_full64[:, :ncols])))
533  left_subset_err32 = max(left_subset_err32, float(np.linalg.norm(p32_m - out_full32[:, :ncols])))
534 
535  # apply_from_right path: Nx16 (N=1..32), columns must equal matrix_size.
536  right64 = np.ascontiguousarray(
537  rng.standard_normal((RECT_COLS_MAX, 1 << 4))
538  + 1j * rng.standard_normal((RECT_COLS_MAX, 1 << 4)),
539  dtype=np.complex128,
540  )
541  right32 = right64.astype(np.complex64)
542 
543  out_right64 = right64.copy()
544  out_right32 = right32.copy()
545  if gate_obj.get_Parameter_Num() == 0:
546  gate_obj.apply_from_right(out_right64, is_f32=False)
547  gate_obj.apply_from_right(out_right32, is_f32=True)
548  else:
549  gate_obj.apply_from_right(out_right64, parameters=p64, is_f32=False)
550  gate_obj.apply_from_right(out_right32, parameters=p32, is_f32=True)
551 
552  right_subset_err64 = 0.0
553  right_subset_err32 = 0.0
554  for nrows in range(1, RECT_COLS_MAX + 1):
555  p64_m = np.ascontiguousarray(right64[:nrows, :].copy())
556  p32_m = np.ascontiguousarray(right32[:nrows, :].copy())
557  if gate_obj.get_Parameter_Num() == 0:
558  gate_obj.apply_from_right(p64_m, is_f32=False)
559  gate_obj.apply_from_right(p32_m, is_f32=True)
560  else:
561  gate_obj.apply_from_right(p64_m, parameters=p64, is_f32=False)
562  gate_obj.apply_from_right(p32_m, parameters=p32, is_f32=True)
563  right_subset_err64 = max(right_subset_err64, float(np.linalg.norm(p64_m - out_right64[:nrows, :])))
564  right_subset_err32 = max(right_subset_err32, float(np.linalg.norm(p32_m - out_right32[:nrows, :])))
565 
566  # apply_to_list path over 16xN for N=1..32.
567  list_in64 = [
568  np.ascontiguousarray(
569  rng.standard_normal((1 << 4, ncols)) + 1j * rng.standard_normal((1 << 4, ncols)),
570  dtype=np.complex128,
571  )
572  for ncols in range(1, RECT_COLS_MAX + 1)
573  ]
574  list_in32 = [m.astype(np.complex64) for m in list_in64]
575  ref64 = [m.copy() for m in list_in64]
576  ref32 = [m.copy() for m in list_in32]
577 
578  if gate_obj.get_Parameter_Num() == 0:
579  gate_obj.apply_to_list(list_in64, parallel=0, is_f32=False)
580  gate_obj.apply_to_list(list_in32, parallel=0, is_f32=True)
581  for m in ref64:
582  gate_obj.apply_to(m, parallel=0, is_f32=False)
583  for m in ref32:
584  gate_obj.apply_to(m, parallel=0, is_f32=True)
585  else:
586  gate_obj.apply_to_list(list_in64, parameters=p64, parallel=0, is_f32=False)
587  gate_obj.apply_to_list(list_in32, parameters=p32, parallel=0, is_f32=True)
588  for m in ref64:
589  gate_obj.apply_to(m, parameters=p64, parallel=0, is_f32=False)
590  for m in ref32:
591  gate_obj.apply_to(m, parameters=p32, parallel=0, is_f32=True)
592 
593  list_err64 = max(float(np.linalg.norm(a - b)) for a, b in zip(list_in64, ref64))
594  list_err32 = max(float(np.linalg.norm(a - b)) for a, b in zip(list_in32, ref32))
595 
596  print(json.dumps({{
597  "status": "ok",
598  "left_subset_err64": left_subset_err64,
599  "left_subset_err32": left_subset_err32,
600  "right_subset_err64": right_subset_err64,
601  "right_subset_err32": right_subset_err32,
602  "list_err64": list_err64,
603  "list_err32": list_err32,
604  }}))
605 except Exception as exc:
606  print(json.dumps({{"status": "exception", "message": str(exc)}}))
607 """
608 
609  proc = subprocess.run(
610  [sys.executable, "-c", script],
611  capture_output=True,
612  text=True,
613  check=False,
614  )
615 
616  if proc.returncode != 0:
617  pytest.fail(
618  f"Gate {gate_name} crashed in rectangular apply* sweep subprocess. "
619  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
620  )
621 
622  result = json.loads(proc.stdout.strip().splitlines()[-1])
623  assert result["status"] == "ok", result
624  assert result["left_subset_err64"] < 1e-10, result
625  assert result["left_subset_err32"] < 5e-5, result
626  assert result["right_subset_err64"] < 1e-10, result
627  assert result["right_subset_err32"] < 5e-5, result
628  assert result["list_err64"] < 1e-10, result
629  assert result["list_err32"] < 5e-5, result
630 
631  @pytest.mark.parametrize("gate_name", DERIVATIVE_GATE_NAMES)
633  script = f"""
634 import json
635 import numpy as np
636 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
637 
638 gate_name = {gate_name!r}
639 
640 try:
641  gate_obj = _instantiate_gate(gate_name)
642  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
643  p32 = p64.astype(np.float32)
644 
645  state64 = np.random.uniform(-1.0, 1.0, (1 << 4,)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4,))
646  state64 = state64.astype(np.complex128)
647  state64 = state64 / np.linalg.norm(state64)
648 
649  state32 = state64.astype(np.complex64)
650  state32 = state32 / np.linalg.norm(state32)
651 
652  d64 = gate_obj.apply_derivate_to(state64.copy(), parameters=p64, parallel=0, is_f32=False)
653  d32 = gate_obj.apply_derivate_to(state32.copy(), parameters=p32, parallel=0, is_f32=True)
654 
655  if not isinstance(d64, list) or not isinstance(d32, list):
656  raise RuntimeError("apply_derivate_to must return a list")
657 
658  for arr in d64:
659  a = np.asarray(arr)
660  if a.dtype != np.complex128:
661  raise RuntimeError("float64 derivative output must be complex128")
662  if a.size != state64.size:
663  raise RuntimeError("float64 derivative output shape mismatch")
664 
665  for arr in d32:
666  a = np.asarray(arr)
667  if a.dtype != np.complex64:
668  raise RuntimeError("float32 derivative output must be complex64")
669  if a.size != state32.size:
670  raise RuntimeError("float32 derivative output shape mismatch")
671 
672  print(json.dumps({{"status": "ok", "n64": len(d64), "n32": len(d32)}}))
673 except Exception as exc:
674  print(json.dumps({{"status": "exception", "message": str(exc)}}))
675 """
676 
677  proc = subprocess.run(
678  [sys.executable, "-c", script],
679  capture_output=True,
680  text=True,
681  check=False,
682  )
683 
684  if proc.returncode != 0:
685  pytest.fail(
686  f"Gate {gate_name} crashed in apply_derivate_to wrapper subprocess. "
687  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
688  )
689 
690  result = json.loads(proc.stdout.strip().splitlines()[-1])
691  assert result["status"] == "ok", result
692 
693  @pytest.mark.parametrize("gate_name", DERIVATIVE_GATE_NAMES)
695  script = f"""
696 import json
697 import numpy as np
698 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
699 
700 gate_name = {gate_name!r}
701 
702 try:
703  gate_obj = _instantiate_gate(gate_name)
704  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
705  p32 = p64.astype(np.float32)
706 
707  state64 = np.random.uniform(-1.0, 1.0, (1 << 4,)) + 1j * np.random.uniform(-1.0, 1.0, (1 << 4,))
708  state64 = state64.astype(np.complex128)
709  state64 = state64 / np.linalg.norm(state64)
710 
711  state32 = state64.astype(np.complex64)
712  state32 = state32 / np.linalg.norm(state32)
713 
714  c64 = gate_obj.apply_to_combined(state64.copy(), parameters=p64, parallel=0, is_f32=False)
715  c32 = gate_obj.apply_to_combined(state32.copy(), parameters=p32, parallel=0, is_f32=True)
716 
717  if not isinstance(c64, list) or not isinstance(c32, list):
718  raise RuntimeError("apply_to_combined must return a list")
719 
720  if len(c64) != len(p64) + 1 or len(c32) != len(p32) + 1:
721  raise RuntimeError("apply_to_combined returned wrong list length")
722 
723  fwd64_ref = state64.copy()
724  gate_obj.apply_to(fwd64_ref, parameters=p64, parallel=0, is_f32=False)
725  fwd32_ref = state32.copy()
726  gate_obj.apply_to(fwd32_ref, parameters=p32, parallel=0, is_f32=True)
727 
728  if np.linalg.norm(np.asarray(c64[0]).reshape(-1) - fwd64_ref.reshape(-1)) > 1e-10:
729  raise RuntimeError("float64 combined forward output mismatch")
730  if np.linalg.norm(np.asarray(c32[0]).astype(np.complex128).reshape(-1) - fwd32_ref.astype(np.complex128).reshape(-1)) > 5e-5:
731  raise RuntimeError("float32 combined forward output mismatch")
732 
733  print(json.dumps({{"status": "ok", "n64": len(c64), "n32": len(c32)}}))
734 except Exception as exc:
735  print(json.dumps({{"status": "exception", "message": str(exc)}}))
736 """
737 
738  proc = subprocess.run(
739  [sys.executable, "-c", script],
740  capture_output=True,
741  text=True,
742  check=False,
743  )
744 
745  if proc.returncode != 0:
746  pytest.fail(
747  f"Gate {gate_name} crashed in apply_to_combined wrapper subprocess. "
748  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
749  )
750 
751  result = json.loads(proc.stdout.strip().splitlines()[-1])
752  assert result["status"] == "ok", result
753 
754  @pytest.mark.parametrize(
755  "gate_name",
756  [name for name in ALL_GATE_NAMES if name not in QISKIT_MATRIX_UNSUPPORTED],
757  )
758  def test_gate_matrix_matches_qiskit(self, gate_name):
759  gate_obj = _instantiate_gate(gate_name)
760  parameters = _parameters_for_gate(gate_obj)
761  gate_matrix = _gate_matrix(gate_obj, parameters)
762 
763  circuit = QuantumCircuit(4)
764  _add_gate_to_qiskit(circuit, gate_name, parameters)
765  qiskit_matrix = utils.get_unitary_from_qiskit_circuit_operator(circuit)
766 
767  _assert_matrices_close(gate_matrix, np.asarray(qiskit_matrix), tol=1e-7)
768 
769  @pytest.mark.parametrize(
770  "gate_name",
771  [name for name in ALL_GATE_NAMES if name not in (QISKIT_EXCLUDED_GATES | {"Gate"})],
772  )
773  def test_qiskit_io_roundtrip_per_gate(self, gate_name):
774  script = f"""
775 import json
776 import numpy as np
777 from squander import Qiskit_IO
778 from squander import utils
779 from squander.gates.qgd_Circuit import qgd_Circuit as Circuit
780 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
781 
782 gate_name = {gate_name!r}
783 
784 try:
785  gate_obj = _instantiate_gate(gate_name)
786  circuit = Circuit(4)
787  circuit.add_Gate(gate_obj)
788  params = _parameters_for_gate(gate_obj)
789 
790  exported = Qiskit_IO.get_Qiskit_Circuit(circuit, params)
791  if exported is None:
792  print(json.dumps({{"status": "unsupported"}}))
793  else:
794  exported_inv = Qiskit_IO.get_Qiskit_Circuit_inverse(circuit, params)
795  circ_rt, params_rt = Qiskit_IO.convert_Qiskit_to_Squander(exported)
796 
797  m1 = np.asarray(circuit.get_Matrix(params))
798  m2 = np.asarray(circ_rt.get_Matrix(params_rt))
799 
800  overlap = np.vdot(m1.reshape(-1), m2.reshape(-1))
801  if np.abs(overlap) > 0:
802  m2 = m2 * np.exp(-1j * np.angle(overlap))
803  matrix_err = float(np.linalg.norm(m1 - m2))
804 
805  forward = np.asarray(utils.get_unitary_from_qiskit_circuit_operator(exported))
806  inverse = np.asarray(utils.get_unitary_from_qiskit_circuit_operator(exported_inv))
807  ident = forward @ inverse
808  ident_raw_err = float(np.linalg.norm(ident - np.eye(ident.shape[0], dtype=np.complex128)))
809  phase = np.angle(np.trace(ident))
810  ident_phase_aligned = ident * np.exp(-1j * phase)
811  ident_phase_err = float(np.linalg.norm(ident_phase_aligned - np.eye(ident.shape[0], dtype=np.complex128)))
812 
813  print(json.dumps({{
814  "status": "ok",
815  "matrix_err": matrix_err,
816  "ident_raw_err": ident_raw_err,
817  "ident_phase_err": ident_phase_err,
818  }}))
819 except Exception as exc:
820  print(json.dumps({{"status": "exception", "message": str(exc)}}))
821 """
822 
823  proc = subprocess.run(
824  [sys.executable, "-c", script],
825  capture_output=True,
826  text=True,
827  check=False,
828  )
829 
830  if proc.returncode != 0:
831  pytest.fail(
832  f"Gate {gate_name} crashed in qiskit_IO roundtrip subprocess. "
833  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
834  )
835 
836  result = json.loads(proc.stdout.strip().splitlines()[-1])
837 
838  assert result["status"] == "ok", result
839  assert result["matrix_err"] < 1e-6, result
840  assert result["ident_raw_err"] < 1e-6 or result["ident_phase_err"] < 1e-6, result
841 
842  if result["ident_raw_err"] >= 1e-6:
843  pytest.fail(
844  f"{gate_name} is only equivalent up to global phase. "
845  f"raw={result['ident_raw_err']}, phase_aligned={result['ident_phase_err']}"
846  )
847 
848  @pytest.mark.parametrize(
849  "gate_name",
850  [name for name in ALL_GATE_NAMES if name != "Gate"],
851  )
852  def test_squander_invert_circuit(self, gate_name):
853  script = f"""
854 import json
855 import numpy as np
856 from squander import utils
857 from squander.gates.qgd_Circuit import qgd_Circuit as Circuit
858 from tests.gates.test_gates import _instantiate_gate, _parameters_for_gate
859 
860 gate_name = {gate_name!r}
861 
862 try:
863  gate_obj = _instantiate_gate(gate_name)
864  circuit = Circuit(4)
865  circuit.add_Gate(gate_obj)
866  params = _parameters_for_gate(gate_obj, dtype=np.float64)
867 
868  inv_circuit, inv_params = utils.invert_circuit(circuit, params)
869 
870  n = 1 << 4
871  M = np.eye(n, dtype=np.complex128)
872  Minv = np.eye(n, dtype=np.complex128)
873  circuit.apply_to(params, M)
874  inv_circuit.apply_to(inv_params, Minv)
875 
876  product = Minv @ M
877  err = float(np.linalg.norm(product - np.eye(n)))
878  print(json.dumps({{"status": "ok", "err": err}}))
879 except Exception as exc:
880  import traceback
881  print(json.dumps({{"status": "exception", "message": str(exc), "trace": traceback.format_exc()}}))
882 """
883 
884  proc = subprocess.run(
885  [sys.executable, "-c", script],
886  capture_output=True,
887  text=True,
888  check=False,
889  )
890 
891  if proc.returncode != 0:
892  pytest.fail(
893  f"Gate {gate_name} crashed in invert_circuit subprocess. "
894  f"returncode={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
895  )
896 
897  result = json.loads(proc.stdout.strip().splitlines()[-1])
898  assert result["status"] == "ok", result
899  assert result["err"] < 1e-8, f"invert_circuit error for {gate_name}: {result['err']}"
900 
901  @pytest.mark.parametrize("gate_name", DERIVATIVE_GATE_NAMES)
903  """extract_parameters should normalise each parameter via fmod(m*p, m*2pi).
904  Values already inside [0, m*2pi) should be unchanged; values above should wrap."""
905  gate_obj = _instantiate_gate(gate_name)
906  pnum = gate_obj.get_Parameter_Num()
907 
908  two_pi = 2.0 * np.pi
909 
910  # Build a circuit-level parameter array; start_idx is 0 by default.
911  # Use one small (in-range) and one large (out-of-range) value per parameter.
912  small_params = np.linspace(0.1, 0.1 * pnum, pnum, dtype=np.float64)
913  large_params = small_params + 10.0 * two_pi # shift by 5 full periods
914 
915  small_extracted = gate_obj.Extract_Parameters(small_params)
916  large_extracted = gate_obj.Extract_Parameters(large_params)
917 
918  assert len(small_extracted) == pnum, "wrong number of extracted parameters"
919  assert len(large_extracted) == pnum
920 
921  # Both in-range and shifted versions should give the same normalised result
922  np.testing.assert_allclose(
923  small_extracted,
924  large_extracted,
925  atol=1e-10,
926  err_msg=f"{gate_name}: extract_parameters did not wrap large parameters to same value as small",
927  )
928 
929  # In-range values should pass through unchanged (fmod(m*p, m*2pi) == m*p when m*p < m*2pi)
930  for i, p in enumerate(small_params):
931  assert small_extracted[i] >= 0.0, f"{gate_name}: extracted param {i} is negative"
932 
933  @pytest.mark.parametrize("gate_name", MULTI_QUBIT_GATE_NAMES)
935  circuit = Circuit(4)
936  circuit.add_Gate(_instantiate_gate(gate_name))
937 
938  params = np.linspace(0.2, 0.2 * circuit.get_Parameter_Num(), circuit.get_Parameter_Num(), dtype=np.float64)
939 
940  cnot_circuit, cnot_params = utils.circuit_to_CNOT_basis(circuit, params)
941 
942  gate_nums = cnot_circuit.get_Gate_Nums()
943  assert gate_nums.get("CNOT", 0) > 0
944 
945  for forbidden_gate in FORBIDDEN_MULTI_QUBIT_GATES_IN_CNOT_BASIS:
946  assert gate_nums.get(forbidden_gate, 0) == 0, (
947  f"{forbidden_gate} still present after CNOT-basis conversion "
948  f"for source gate {gate_name}"
949  )
950 
951  original_matrix = np.asarray(circuit.get_Matrix(params))
952  transpiled_matrix = np.asarray(cnot_circuit.get_Matrix(cnot_params))
953  _assert_matrices_close(original_matrix, transpiled_matrix, tol=1e-6)
954 
955 
957  """Direct in-process scalar-path checks for gate methods.
958 
959  The subprocess tests above are crash-isolation sweeps. These tests stay in-process
960  so dtype mistakes and scalar dispatch regressions are reported at the failing call.
961  """
962 
963  @pytest.fixture(scope="class")
964  def scalar_inputs(self):
965  rng_state = np.random.default_rng(42)
966  state = rng_state.standard_normal(1 << 4) + 1j * rng_state.standard_normal(1 << 4)
967  state = (state / np.linalg.norm(state)).astype(np.complex128)
968 
969  rng_matrix = np.random.default_rng(7)
970  matrix = rng_matrix.standard_normal((1 << 4, 1 << 4)) + 1j * rng_matrix.standard_normal((1 << 4, 1 << 4))
971  return state, matrix.astype(np.complex128)
972 
973  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
975  gate_obj = _instantiate_gate(gate_name)
976  params = _parameters_for_gate(gate_obj, dtype=np.float64)
977  matrix = _get_matrix_with_precision(gate_obj, params, is_f32=False)
978 
979  assert matrix.dtype == np.complex128
980  product = matrix.conj().T @ matrix
981  assert np.linalg.norm(product - np.eye(matrix.shape[0])) < 1e-8
982 
983  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
984  def test_get_matrix_scalar_f32_parity(self, gate_name):
985  gate_obj = _instantiate_gate(gate_name)
986  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
987  p32 = p64.astype(np.float32)
988 
989  m64 = _get_matrix_with_precision(gate_obj, p64, is_f32=False)
990  m32 = _get_matrix_with_precision(gate_obj, p32, is_f32=True)
991 
992  assert m32.dtype == np.complex64
993  assert np.linalg.norm(m32 - m64.astype(np.complex64)) < F32_TOL
994 
995  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
996  def test_apply_to_state_scalar_matches_matrix_and_f32_parity(self, gate_name, scalar_inputs):
997  state64, _ = scalar_inputs
998  gate_obj = _instantiate_gate(gate_name)
999  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
1000  p32 = p64.astype(np.float32)
1001 
1002  matrix = _get_matrix_with_precision(gate_obj, p64, is_f32=False)
1003  result64 = _apply_to_state_with_precision(gate_obj, state64, p64, is_f32=False)
1004  result32 = _apply_to_state_with_precision(gate_obj, state64.astype(np.complex64), p32, is_f32=True)
1005 
1006  assert np.linalg.norm(result64 - matrix @ state64) < 1e-8
1007  assert np.linalg.norm(result32 - result64.astype(np.complex64)) < F32_TOL
1008 
1009  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
1011  _, matrix64 = scalar_inputs
1012  gate_obj = _instantiate_gate(gate_name)
1013  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
1014  p32 = p64.astype(np.float32)
1015 
1016  gate_matrix = _get_matrix_with_precision(gate_obj, p64, is_f32=False)
1017  result64 = _apply_to_matrix_with_precision(gate_obj, matrix64, p64, is_f32=False)
1018  result32 = _apply_to_matrix_with_precision(gate_obj, matrix64.astype(np.complex64), p32, is_f32=True)
1019 
1020  assert np.linalg.norm(result64 - gate_matrix @ matrix64) < 1e-8
1021  assert np.linalg.norm(result32 - result64.astype(np.complex64)) < F32_TOL
1022 
1023  @pytest.mark.parametrize("gate_name", [name for name in ALL_GATE_NAMES if name != "Gate"])
1025  _, matrix64 = scalar_inputs
1026  gate_obj = _instantiate_gate(gate_name)
1027  p64 = _parameters_for_gate(gate_obj, dtype=np.float64)
1028  p32 = p64.astype(np.float32)
1029 
1030  gate_matrix = _get_matrix_with_precision(gate_obj, p64, is_f32=False)
1031  result64 = _apply_from_right_with_precision(gate_obj, matrix64, p64, is_f32=False)
1032  result32 = _apply_from_right_with_precision(gate_obj, matrix64.astype(np.complex64), p32, is_f32=True)
1033 
1034  assert np.linalg.norm(result64 - matrix64 @ gate_matrix) < 1e-8
1035  assert np.linalg.norm(result32 - result64.astype(np.complex64)) < F32_TOL
1036 
1037 
1039  """Verify that each parametric gate's apply_derivate_to matches a central finite difference."""
1040 
1041  FD_EPS = 1e-5
1042  FD_TOL = 1e-5
1043 
1044  @pytest.mark.parametrize("gate_name", DERIVATIVE_GATE_NAMES)
1045  def test_gate_derivative_fd_f64(self, gate_name):
1046  """Analytic derivative must agree with finite difference (float64)."""
1047  gate_obj = _instantiate_gate(gate_name)
1048  pnum = gate_obj.get_Parameter_Num()
1049  params = _parameters_for_gate(gate_obj)
1050 
1051  dim = np.asarray(gate_obj.get_Matrix(params)).shape[0]
1052  mat = np.eye(dim, dtype=np.complex128)
1053  derivs = gate_obj.apply_derivate_to(mat.copy(), parameters=params, parallel=0, is_f32=False)
1054 
1055  assert len(derivs) == pnum, f"{gate_name}: got {len(derivs)} derivatives, expected {pnum}"
1056 
1057  eps = self.FD_EPS
1058  for k in range(pnum):
1059  p_plus = params.copy(); p_plus[k] += eps
1060  p_minus = params.copy(); p_minus[k] -= eps
1061  fd = (np.asarray(gate_obj.get_Matrix(p_plus)) - np.asarray(gate_obj.get_Matrix(p_minus))) / (2 * eps)
1062  err = float(np.linalg.norm(np.asarray(derivs[k]) - fd))
1063  assert err < self.FD_TOL, (
1064  f"{gate_name} param {k}: analytic vs FD error = {err:.3e} > {self.FD_TOL:.1e}"
1065  )
def test_gate_apply_to_list_float32_float64_parity(self, gate_name)
Definition: test_gates.py:433
def test_gate_get_matrix_float32_float64_parity(self, gate_name)
Definition: test_gates.py:336
def _apply_to_matrix_with_precision(gate_obj, matrix, parameters, is_f32)
Definition: test_gates.py:136
def _assert_matrices_close(a, b, tol=1e-8)
Definition: test_gates.py:154
def test_gate_apply_derivate_wrapper_smoke(self, gate_name)
Definition: test_gates.py:632
def test_get_matrix_scalar_f64_unitary(self, gate_name)
Definition: test_gates.py:974
def _apply_gate(gate_obj, state, parameters, is_f32=False, parallel=0)
Definition: test_gates.py:114
def _get_matrix_with_precision(gate_obj, parameters, is_f32)
Definition: test_gates.py:121
def test_squander_invert_circuit(self, gate_name)
Definition: test_gates.py:852
def test_get_matrix_scalar_f32_parity(self, gate_name)
Definition: test_gates.py:984
def test_gate_apply_to_combined_wrapper_smoke(self, gate_name)
Definition: test_gates.py:694
def test_extract_parameters_wraps_out_of_range(self, gate_name)
Definition: test_gates.py:902
def test_apply_from_right_scalar_matches_matrix_and_f32_parity(self, gate_name, scalar_inputs)
Definition: test_gates.py:1024
def _apply_to_state_with_precision(gate_obj, state, parameters, is_f32)
Definition: test_gates.py:127
def test_apply_to_state_scalar_matches_matrix_and_f32_parity(self, gate_name, scalar_inputs)
Definition: test_gates.py:996
def test_apply_to_matrix_scalar_matches_matrix_and_f32_parity(self, gate_name, scalar_inputs)
Definition: test_gates.py:1010
def _add_gate_to_qiskit(circuit, gate_name, parameters)
Definition: test_gates.py:162
def _discover_parameterized_gate_names()
Definition: test_gates.py:61
def _discover_multi_qubit_gate_names()
Definition: test_gates.py:72
def test_gate_apply_to_float32_float64_parity(self, gate_name)
Definition: test_gates.py:282
def test_gate_constructor_and_base_methods(self, gate_name)
Definition: test_gates.py:234
def _apply_from_right_with_precision(gate_obj, matrix, parameters, is_f32)
Definition: test_gates.py:145
def test_gate_matrix_matches_qiskit(self, gate_name)
Definition: test_gates.py:758
def _instantiate_gate(gate_name, qbit_num=4)
Definition: test_gates.py:83
string method
[create decomposition class] creating a class to decompose the unitary
def _gate_matrix(gate_obj, parameters)
Definition: test_gates.py:108
def test_qiskit_io_roundtrip_per_gate(self, gate_name)
Definition: test_gates.py:773
def _parameters_for_gate(gate_obj, dtype=np.float64)
Definition: test_gates.py:101
def test_circuit_to_cnot_basis_removes_non_cnot_multi_qubit_gates(self, gate_name)
Definition: test_gates.py:934
def test_gate_apply_rectangular_sweep_paths(self, gate_name)
Definition: test_gates.py:489
def test_operation_block_add_operations(self)
Definition: test_gates.py:224
def test_gate_apply_from_right_float32_float64_parity(self, gate_name)
Definition: test_gates.py:382