tequila-basic 1.9.9__py3-none-any.whl → 1.9.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. tequila/__init__.py +29 -14
  2. tequila/apps/__init__.py +14 -5
  3. tequila/apps/_unary_state_prep_impl.py +145 -112
  4. tequila/apps/adapt/__init__.py +9 -1
  5. tequila/apps/adapt/adapt.py +154 -113
  6. tequila/apps/krylov/__init__.py +1 -1
  7. tequila/apps/krylov/krylov.py +23 -21
  8. tequila/apps/robustness/helpers.py +10 -6
  9. tequila/apps/robustness/interval.py +238 -156
  10. tequila/apps/unary_state_prep.py +29 -23
  11. tequila/autograd_imports.py +8 -5
  12. tequila/circuit/__init__.py +2 -1
  13. tequila/circuit/_gates_impl.py +135 -67
  14. tequila/circuit/circuit.py +163 -79
  15. tequila/circuit/compiler.py +114 -105
  16. tequila/circuit/gates.py +288 -120
  17. tequila/circuit/gradient.py +35 -23
  18. tequila/circuit/noise.py +83 -74
  19. tequila/circuit/postselection.py +120 -0
  20. tequila/circuit/pyzx.py +10 -6
  21. tequila/circuit/qasm.py +201 -83
  22. tequila/circuit/qpic.py +63 -61
  23. tequila/grouping/binary_rep.py +148 -146
  24. tequila/grouping/binary_utils.py +84 -75
  25. tequila/grouping/compile_groups.py +334 -230
  26. tequila/grouping/ev_utils.py +77 -41
  27. tequila/grouping/fermionic_functions.py +383 -308
  28. tequila/grouping/fermionic_methods.py +170 -123
  29. tequila/grouping/overlapping_methods.py +69 -52
  30. tequila/hamiltonian/paulis.py +12 -13
  31. tequila/hamiltonian/paulistring.py +1 -1
  32. tequila/hamiltonian/qubit_hamiltonian.py +45 -35
  33. tequila/ml/__init__.py +1 -0
  34. tequila/ml/interface_torch.py +19 -16
  35. tequila/ml/ml_api.py +11 -10
  36. tequila/ml/utils_ml.py +12 -11
  37. tequila/objective/__init__.py +8 -3
  38. tequila/objective/braket.py +55 -47
  39. tequila/objective/objective.py +87 -55
  40. tequila/objective/qtensor.py +36 -27
  41. tequila/optimizers/__init__.py +31 -23
  42. tequila/optimizers/_containers.py +11 -7
  43. tequila/optimizers/optimizer_base.py +111 -83
  44. tequila/optimizers/optimizer_gd.py +258 -231
  45. tequila/optimizers/optimizer_gpyopt.py +56 -42
  46. tequila/optimizers/optimizer_scipy.py +157 -112
  47. tequila/quantumchemistry/__init__.py +66 -38
  48. tequila/quantumchemistry/chemistry_tools.py +393 -209
  49. tequila/quantumchemistry/encodings.py +121 -13
  50. tequila/quantumchemistry/madness_interface.py +170 -96
  51. tequila/quantumchemistry/orbital_optimizer.py +86 -41
  52. tequila/quantumchemistry/psi4_interface.py +166 -97
  53. tequila/quantumchemistry/pyscf_interface.py +70 -23
  54. tequila/quantumchemistry/qc_base.py +866 -414
  55. tequila/simulators/__init__.py +0 -3
  56. tequila/simulators/simulator_api.py +247 -105
  57. tequila/simulators/simulator_aqt.py +102 -0
  58. tequila/simulators/simulator_base.py +147 -53
  59. tequila/simulators/simulator_cirq.py +58 -42
  60. tequila/simulators/simulator_cudaq.py +600 -0
  61. tequila/simulators/simulator_ddsim.py +390 -0
  62. tequila/simulators/simulator_mqp.py +30 -0
  63. tequila/simulators/simulator_pyquil.py +190 -171
  64. tequila/simulators/simulator_qibo.py +95 -87
  65. tequila/simulators/simulator_qiskit.py +119 -107
  66. tequila/simulators/simulator_qlm.py +52 -26
  67. tequila/simulators/simulator_qulacs.py +74 -52
  68. tequila/simulators/simulator_spex.py +95 -60
  69. tequila/simulators/simulator_symbolic.py +6 -5
  70. tequila/simulators/test_spex_simulator.py +8 -11
  71. tequila/tools/convenience.py +4 -4
  72. tequila/tools/qng.py +72 -64
  73. tequila/tools/random_generators.py +38 -34
  74. tequila/utils/bitstrings.py +7 -7
  75. tequila/utils/exceptions.py +19 -5
  76. tequila/utils/joined_transformation.py +8 -10
  77. tequila/utils/keymap.py +0 -5
  78. tequila/utils/misc.py +6 -4
  79. tequila/version.py +1 -1
  80. tequila/wavefunction/qubit_wavefunction.py +47 -28
  81. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
  82. tequila_basic-1.9.10.dist-info/RECORD +93 -0
  83. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
  84. tequila_basic-1.9.9.dist-info/RECORD +0 -88
  85. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
  86. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
tequila/circuit/qasm.py CHANGED
@@ -5,6 +5,7 @@ OPENQASM version 2.0 specification from:
5
5
  A. W. Cross, L. S. Bishop, J. A. Smolin, and J. M. Gambetta, e-print arXiv:1707.03429v2 [quant-ph] (2017).
6
6
  https://arxiv.org/pdf/1707.03429v2.pdf
7
7
  """
8
+
8
9
  from tequila import TequilaException
9
10
  from tequila.circuit import QCircuit
10
11
  from tequila.circuit.compiler import CircuitCompiler
@@ -14,7 +15,9 @@ from typing import Dict
14
15
  import typing
15
16
 
16
17
 
17
- def export_open_qasm(circuit: QCircuit, variables=None, version: str = "2.0", filename: str = None, zx_calculus: bool = False) -> str:
18
+ def export_open_qasm(
19
+ circuit: QCircuit, variables=None, version: str = "2.0", filename: str = None, zx_calculus: bool = False
20
+ ) -> str:
18
21
  """
19
22
  Allow export to different versions of OpenQASM
20
23
 
@@ -31,9 +34,10 @@ def export_open_qasm(circuit: QCircuit, variables=None, version: str = "2.0", fi
31
34
 
32
35
  if version == "2.0":
33
36
  result = convert_to_open_qasm_2(circuit=circuit, variables=variables, zx_calculus=zx_calculus)
37
+ elif version.startswith("3"):
38
+ result = convert_to_open_qasm_3(circuit=circuit, variables=variables, zx_calculus=zx_calculus)
34
39
  else:
35
40
  return "Unsupported OpenQASM version : " + version
36
- # TODO: export to version 3
37
41
 
38
42
  if filename is not None:
39
43
  with open(filename, "w") as file:
@@ -58,13 +62,112 @@ def import_open_qasm(qasm_code: str, version: str = "2.0", rigorous: bool = True
58
62
 
59
63
  if version == "2.0":
60
64
  result = parse_from_open_qasm_2(qasm_code=qasm_code, rigorous=rigorous)
65
+ elif version.startswith("3"):
66
+ result = parse_from_open_qasm_3(qasm_code=qasm_code, rigorous=rigorous)
61
67
  else:
62
68
  return "Unsupported OpenQASM version : " + version
63
- # TODO: export to version 3
64
69
 
65
70
  return result
66
71
 
67
72
 
73
+ # --- QASM 3 support skeletons ---
74
+ def convert_to_open_qasm_3(circuit: QCircuit, variables=None, zx_calculus: bool = False) -> str:
75
+ """
76
+ Allow export to OpenQASM version 3.0 (minimal, symbolic variables supported)
77
+ Args:
78
+ circuit: to be exported to OpenQASM
79
+ variables: optional dictionary with values for variables
80
+ zx_calculus: indicate if y-gates must be transformed to xz equivalents
81
+ Returns:
82
+ str: OpenQASM 3 string
83
+ """
84
+ # Compile circuit (do not resolve variables)
85
+ compiler = CircuitCompiler(
86
+ multitarget=True,
87
+ multicontrol=False,
88
+ trotterized=True,
89
+ generalized_rotation=True,
90
+ exponential_pauli=True,
91
+ controlled_exponential_pauli=True,
92
+ hadamard_power=True,
93
+ controlled_power=True,
94
+ power=True,
95
+ toffoli=True,
96
+ controlled_phase=True,
97
+ phase=True,
98
+ phase_to_z=True,
99
+ controlled_rotation=True,
100
+ swap=True,
101
+ cc_max=True,
102
+ gradient_mode=False,
103
+ ry_gate=zx_calculus,
104
+ y_gate=zx_calculus,
105
+ ch_gate=zx_calculus,
106
+ )
107
+
108
+ compiled = compiler(circuit, variables=None)
109
+
110
+ # QASM 3 header
111
+ result = "OPENQASM 3;\n"
112
+ result += "qubit[{}] q;\n".format(compiled.n_qubits)
113
+
114
+ # Export symbolic variables as QASM 3 let statements
115
+ # Only primitive variables (no functions) for now
116
+ variables_in_circuit = circuit.extract_variables()
117
+ if variables_in_circuit:
118
+ for v in sorted(variables_in_circuit):
119
+ result += f"let {v}: float;\n"
120
+
121
+ # Export gates
122
+ for g in compiled.gates:
123
+ # Controls
124
+ control_str = ""
125
+ if g.is_controlled():
126
+ if len(g.control) > 1:
127
+ raise TequilaException(
128
+ "Multi-controls beyond 1 not yet supported for QASM 3 export. Gate was:\n{}".format(g)
129
+ )
130
+ control_str = f"ctrl @ "
131
+
132
+ # Gate name and parameter
133
+ gate_name = g.name.lower()
134
+ param_str = ""
135
+ if hasattr(g, "parameter") and g.parameter is not None:
136
+ # Try to get symbolic expression as string
137
+ try:
138
+ param = g.parameter(None)
139
+ if hasattr(param, "name"):
140
+ param_str = f"({param.name})"
141
+ else:
142
+ param_str = f"({param})"
143
+ except Exception:
144
+ # fallback: use str(g.parameter)
145
+ param_str = f"({g.parameter})"
146
+
147
+ # Targets
148
+ for t in g.target:
149
+ if control_str:
150
+ # QASM 3 control syntax: ctrl @ gate ...
151
+ result += f"{control_str}{gate_name}{param_str} q[{t}];\n"
152
+ else:
153
+ result += f"{gate_name}{param_str} q[{t}];\n"
154
+
155
+ return result
156
+
157
+
158
+ def parse_from_open_qasm_3(qasm_code: str, rigorous: bool = True) -> QCircuit:
159
+ """
160
+ Parse OpenQASM 3.0 code into a QCircuit (skeleton)
161
+ Args:
162
+ qasm_code: string with the OpenQASM 3 code
163
+ rigorous: indicates whether the QASM code should be read rigorously
164
+ Returns:
165
+ QCircuit: equivalent to the OpenQASM code received
166
+ """
167
+ # TODO: Implement full QASM 3 import with symbolic variable support
168
+ raise NotImplementedError("OpenQASM 3 import is not yet implemented.")
169
+
170
+
68
171
  def import_open_qasm_from_file(filename: str, version: str = "2.0", rigorous: bool = True) -> QCircuit:
69
172
  """
70
173
  Allow import from different versions of OpenQASM from a file
@@ -102,32 +205,36 @@ def convert_to_open_qasm_2(circuit: QCircuit, variables=None, zx_calculus: bool
102
205
  if variables is None and not (len(circuit.extract_variables()) == 0):
103
206
  raise TequilaException(
104
207
  "You called export_open_qasm for a parametrized type but forgot to pass down the variables: {}".format(
105
- circuit.extract_variables()))
106
-
107
- compiler = CircuitCompiler(multitarget=True,
108
- multicontrol=False,
109
- trotterized=True,
110
- generalized_rotation=True,
111
- exponential_pauli=True,
112
- controlled_exponential_pauli=True,
113
- hadamard_power=True,
114
- controlled_power=True,
115
- power=True,
116
- toffoli=True,
117
- controlled_phase=True,
118
- phase=True,
119
- phase_to_z=True,
120
- controlled_rotation=True,
121
- swap=True,
122
- cc_max=True,
123
- gradient_mode=False,
124
- ry_gate=zx_calculus,
125
- y_gate=zx_calculus,
126
- ch_gate=zx_calculus)
208
+ circuit.extract_variables()
209
+ )
210
+ )
211
+
212
+ compiler = CircuitCompiler(
213
+ multitarget=True,
214
+ multicontrol=False,
215
+ trotterized=True,
216
+ generalized_rotation=True,
217
+ exponential_pauli=True,
218
+ controlled_exponential_pauli=True,
219
+ hadamard_power=True,
220
+ controlled_power=True,
221
+ power=True,
222
+ toffoli=True,
223
+ controlled_phase=True,
224
+ phase=True,
225
+ phase_to_z=True,
226
+ controlled_rotation=True,
227
+ swap=True,
228
+ cc_max=True,
229
+ gradient_mode=False,
230
+ ry_gate=zx_calculus,
231
+ y_gate=zx_calculus,
232
+ ch_gate=zx_calculus,
233
+ )
127
234
 
128
235
  compiled = compiler(circuit, variables=None)
129
236
 
130
- result = "OPENQASM 2.0;\ninclude \"qelib1.inc\";\n"
237
+ result = 'OPENQASM 2.0;\ninclude "qelib1.inc";\n'
131
238
 
132
239
  qubits_names: Dict[int, str] = {}
133
240
  for q in compiled.qubits:
@@ -138,16 +245,15 @@ def convert_to_open_qasm_2(circuit: QCircuit, variables=None, zx_calculus: bool
138
245
  result += "creg c[" + str(compiled.n_qubits) + "];\n"
139
246
 
140
247
  for g in compiled.gates:
141
-
142
- control_str = ''
248
+ control_str = ""
143
249
  if g.is_controlled():
144
-
145
250
  if len(g.control) > 2:
146
251
  raise TequilaException(
147
- "Multi-controls beyond 2 not yet supported for OpenQASM 2.0. Gate was:\n{}".format(g))
252
+ "Multi-controls beyond 2 not yet supported for OpenQASM 2.0. Gate was:\n{}".format(g)
253
+ )
148
254
 
149
255
  controls = list(map(lambda c: qubits_names[c], g.control))
150
- control_str = ','.join(controls) + ','
256
+ control_str = ",".join(controls) + ","
151
257
 
152
258
  gate_name = name_and_params(g, variables)
153
259
  for t in g.target:
@@ -187,13 +293,12 @@ def name_and_params(g, variables):
187
293
 
188
294
 
189
295
  def parse_from_open_qasm_2(qasm_code: str, rigorous: bool = True) -> QCircuit:
190
-
191
296
  lines = qasm_code.splitlines()
192
297
  clean_code = []
193
298
  # ignore comments
194
299
  for line in lines:
195
300
  if line.find("//") != -1:
196
- clean_line = line[0:line.find("//")].strip()
301
+ clean_line = line[0 : line.find("//")].strip()
197
302
  else:
198
303
  clean_line = line.strip()
199
304
  if clean_line:
@@ -217,9 +322,9 @@ def parse_from_open_qasm_2(qasm_code: str, rigorous: bool = True) -> QCircuit:
217
322
  if i == -1:
218
323
  break
219
324
  j = code_circuit.find("}", i)
220
- custom_name, custom_circuit = parse_custom_gate(code_circuit[i:j + 1], custom_gates_map=custom_gates_map)
325
+ custom_name, custom_circuit = parse_custom_gate(code_circuit[i : j + 1], custom_gates_map=custom_gates_map)
221
326
  custom_gates_map[custom_name] = custom_circuit
222
- code_circuit = code_circuit[:i] + code_circuit[j + 1:]
327
+ code_circuit = code_circuit[:i] + code_circuit[j + 1 :]
223
328
 
224
329
  # parse regular commands
225
330
  commands = [s.strip() for s in code_circuit.split(";") if s.strip()]
@@ -234,7 +339,7 @@ def parse_from_open_qasm_2(qasm_code: str, rigorous: bool = True) -> QCircuit:
234
339
  return circuit
235
340
 
236
341
 
237
- def parse_custom_gate(gate_custom: str, custom_gates_map: Dict[str, QCircuit]) -> (str, QCircuit):
342
+ def parse_custom_gate(gate_custom: str, custom_gates_map: Dict[str, QCircuit]) -> tuple[str, QCircuit]:
238
343
  """
239
344
  Parse custom gates code
240
345
 
@@ -247,9 +352,9 @@ def parse_custom_gate(gate_custom: str, custom_gates_map: Dict[str, QCircuit]) -
247
352
  if "(" in spec:
248
353
  i = spec.find("(")
249
354
  j = spec.find(")")
250
- if spec[i + 1:j].strip():
355
+ if spec[i + 1 : j].strip():
251
356
  raise TequilaException("Parameters for custom gates not supported: {}".format(spec))
252
- spec = spec[:i] + spec[j + 1:]
357
+ spec = spec[:i] + spec[j + 1 :]
253
358
 
254
359
  spec = spec.strip()
255
360
 
@@ -261,7 +366,7 @@ def parse_custom_gate(gate_custom: str, custom_gates_map: Dict[str, QCircuit]) -
261
366
  raise TequilaException("Custom gate specification doesn't have any arguments: {}".format(spec))
262
367
 
263
368
  custom_qregisters: Dict[str, int] = {}
264
- for qarg in qargs.split(','):
369
+ for qarg in qargs.split(","):
265
370
  custom_qregisters[qarg] = len(custom_qregisters)
266
371
 
267
372
  body = body[:-1].strip()
@@ -302,7 +407,7 @@ def parse_command(command: str, custom_gates_map: Dict[str, QCircuit], qregister
302
407
  return None
303
408
 
304
409
  for arg in args:
305
- if not (arg in qregisters or arg in [key.split("[",1)[0] for key in qregisters.keys()]):
410
+ if not (arg in qregisters or arg in [key.split("[", 1)[0] for key in qregisters.keys()]):
306
411
  raise TequilaException("Invalid register {}".format(arg))
307
412
 
308
413
  if name in custom_gates_map:
@@ -315,7 +420,7 @@ def parse_command(command: str, custom_gates_map: Dict[str, QCircuit], qregister
315
420
  if name in ("x", "y", "z", "h", "cx", "cy", "cz", "ch"):
316
421
  target = get_qregister(args[0], qregisters)
317
422
  control = None
318
- if name[0].lower() == 'c':
423
+ if name[0].lower() == "c":
319
424
  control = get_qregister(args[0], qregisters)
320
425
  target = get_qregister(args[1], qregisters)
321
426
  name = name[1]
@@ -328,57 +433,70 @@ def parse_command(command: str, custom_gates_map: Dict[str, QCircuit], qregister
328
433
  target = get_qregister(args[2], qregisters)
329
434
  return G(control=control, target=target)
330
435
 
331
- if name.startswith("rx(") or name.startswith("ry(") or name.startswith("rz(") or \
332
- name.startswith("crx(") or name.startswith("cry(") or name.startswith("crz("):
436
+ if (
437
+ name.startswith("rx(")
438
+ or name.startswith("ry(")
439
+ or name.startswith("rz(")
440
+ or name.startswith("crx(")
441
+ or name.startswith("cry(")
442
+ or name.startswith("crz(")
443
+ ):
333
444
  angle = get_angle(name)[0]
334
- i = name.find('(')
445
+ i = name.find("(")
335
446
  name = name[0:i]
336
447
  name = name.upper()
337
448
  name = [x for x in name]
338
449
  name[-1] = name[-1].lower()
339
450
  name = "".join(name)
340
451
  G = getattr(gates, name)
341
- return G(angle=angle,control=get_qregister(args[0], qregisters) if name[0] == 'C' else None,target=get_qregister(args[1 if name[0] == 'C' else 0], qregisters))
342
-
452
+ return G(
453
+ angle=angle,
454
+ control=get_qregister(args[0], qregisters) if name[0] == "C" else None,
455
+ target=get_qregister(args[1 if name[0] == "C" else 0], qregisters),
456
+ )
457
+
343
458
  if name.startswith("U("):
344
459
  angles = get_angle(name)
345
- return gates.U(theta=angles[0], phi=angles[1], lambd=angles[2],
346
- control=None,
347
- target=get_qregister(args[0], qregisters))
460
+ return gates.U(
461
+ theta=angles[0], phi=angles[1], lambd=angles[2], control=None, target=get_qregister(args[0], qregisters)
462
+ )
348
463
  if name.startswith("u1("):
349
464
  angles = get_angle(name)
350
- return gates.u1(lambd=angles[0],
351
- control=None,
352
- target=get_qregister(args[0], qregisters))
465
+ return gates.u1(lambd=angles[0], control=None, target=get_qregister(args[0], qregisters))
353
466
  if name.startswith("u2("):
354
467
  angles = get_angle(name)
355
- return gates.u2(phi=angles[0], lambd=angles[1],
356
- control=None,
357
- target=get_qregister(args[0], qregisters))
468
+ return gates.u2(phi=angles[0], lambd=angles[1], control=None, target=get_qregister(args[0], qregisters))
358
469
  if name.startswith("u3("):
359
470
  angles = get_angle(name)
360
- return gates.u3(theta=angles[0], phi=angles[1], lambd=angles[2],
361
- control=None,
362
- target=get_qregister(args[0], qregisters))
471
+ return gates.u3(
472
+ theta=angles[0], phi=angles[1], lambd=angles[2], control=None, target=get_qregister(args[0], qregisters)
473
+ )
363
474
  if name.startswith("cu1("):
364
475
  angles = get_angle(name)
365
- return gates.u1(lambd=angles[0],
366
- control=get_qregister(args[0], qregisters),
367
- target=get_qregister(args[1], qregisters))
476
+ return gates.u1(
477
+ lambd=angles[0], control=get_qregister(args[0], qregisters), target=get_qregister(args[1], qregisters)
478
+ )
368
479
  if name.startswith("cu2("):
369
480
  angles = get_angle(name)
370
- return gates.u2(phi=angles[0], lambd=angles[1],
371
- control=get_qregister(args[0], qregisters),
372
- target=get_qregister(args[1], qregisters))
481
+ return gates.u2(
482
+ phi=angles[0],
483
+ lambd=angles[1],
484
+ control=get_qregister(args[0], qregisters),
485
+ target=get_qregister(args[1], qregisters),
486
+ )
373
487
  if name.startswith("cu3("):
374
488
  angles = get_angle(name)
375
- return gates.u3(theta=angles[0], phi=angles[1], lambd=angles[2],
376
- control=get_qregister(args[0], qregisters),
377
- target=get_qregister(args[1], qregisters))
489
+ return gates.u3(
490
+ theta=angles[0],
491
+ phi=angles[1],
492
+ lambd=angles[2],
493
+ control=get_qregister(args[0], qregisters),
494
+ target=get_qregister(args[1], qregisters),
495
+ )
378
496
  if name in ("s", "t", "sdg", "tdg"):
379
- g = gates.Phase(angle=pi / (2 if name.startswith("s") else 4),
380
- control=None,
381
- target=get_qregister(args[0], qregisters))
497
+ g = gates.Phase(
498
+ angle=pi / (2 if name.startswith("s") else 4), control=None, target=get_qregister(args[0], qregisters)
499
+ )
382
500
  if name.find("dg") != -1:
383
501
  g = g.dagger()
384
502
  return g
@@ -401,31 +519,32 @@ def get_qregister(qreg: str, qregisters: Dict[str, int]) -> typing.Union[list, i
401
519
  qreg_tequila = qregisters[qreg]
402
520
  return qreg_tequila
403
521
 
522
+
404
523
  def get_angle(name: str) -> list:
405
- i = name.find('(')
406
- j = name.find(')')
524
+ i = name.find("(")
525
+ j = name.find(")")
407
526
  if j == -1:
408
527
  raise TequilaException("Invalid specification {}".format(name))
409
- angles_str = name[i+1:j].split(',')
528
+ angles_str = name[i + 1 : j].split(",")
410
529
  angles = []
411
530
  for angle in angles_str:
412
531
  try:
413
532
  phase = float(angle)
414
533
  except ValueError:
415
- if angle.find('pi') == -1:
534
+ if angle.find("pi") == -1:
416
535
  raise TequilaException("Invalid specification {}".format(name))
417
- angle = angle.replace('pi', '')
536
+ angle = angle.replace("pi", "")
418
537
  try:
419
538
  sign = 1
420
539
  div = 1
421
- if angle.find('-') != -1:
422
- angle = angle.replace('-', '')
540
+ if angle.find("-") != -1:
541
+ angle = angle.replace("-", "")
423
542
  sign = -1
424
- if angle.find('/') != -1:
425
- div = float(angle[angle.index('/')+1:])
426
- angle = angle[:angle.index('/')]
427
- if angle.find('*') != -1:
428
- angle = angle.replace('*', '')
543
+ if angle.find("/") != -1:
544
+ div = float(angle[angle.index("/") + 1 :])
545
+ angle = angle[: angle.index("/")]
546
+ if angle.find("*") != -1:
547
+ angle = angle.replace("*", "")
429
548
  phase = sign * float(angle) * pi / div
430
549
  elif len(angle) == 0:
431
550
  phase = sign * pi / div
@@ -435,4 +554,3 @@ def get_angle(name: str) -> list:
435
554
  raise TequilaException("Invalid specification {}".format(name))
436
555
  angles.append(phase)
437
556
  return angles
438
-
tequila/circuit/qpic.py CHANGED
@@ -5,7 +5,8 @@ https://github.com/qpic/qpic/blob/master/doc/qpic_doc.pdf
5
5
 
6
6
  from tequila.objective.objective import FixedVariable
7
7
 
8
- import subprocess, numpy
8
+ import subprocess
9
+ import numpy
9
10
  from shutil import which
10
11
 
11
12
  import numbers
@@ -18,10 +19,10 @@ def assign_name(parameter):
18
19
  if isinstance(parameter, tuple):
19
20
  return "\\theta"
20
21
  if hasattr(parameter, "extract_variables"):
21
- return repr(parameter.extract_variables()).lstrip('[').rstrip(']')
22
+ return repr(parameter.extract_variables()).lstrip("[").rstrip("]")
22
23
  if isinstance(parameter, FixedVariable):
23
24
  for i in [1, 2, 3, 4]:
24
- if numpy.isclose(numpy.abs(float(parameter)), numpy.pi / i, atol=1.e-4):
25
+ if numpy.isclose(numpy.abs(float(parameter)), numpy.pi / i, atol=1.0e-4):
25
26
  if float(parameter) < 0.0:
26
27
  return "-\\pi/{}".format(i)
27
28
  else:
@@ -30,14 +31,26 @@ def assign_name(parameter):
30
31
 
31
32
  try:
32
33
  return repr(parameter)
33
- except:
34
+ except Exception:
34
35
  return str(parameter)
35
36
 
36
37
 
37
- def export_to_qpic(circuit, filename=None, filepath=None, always_use_generators=True,
38
- decompose_control_generators=False,
39
- group_together=False, qubit_names=None, mark_parametrized_gates=True, gatecolor1="tq",
40
- textcolor1="white", gatecolor2="guo", textcolor2="black", *args, **kwargs) -> str:
38
+ def export_to_qpic(
39
+ circuit,
40
+ filename=None,
41
+ filepath=None,
42
+ always_use_generators=True,
43
+ decompose_control_generators=False,
44
+ group_together=False,
45
+ qubit_names=None,
46
+ mark_parametrized_gates=True,
47
+ gatecolor1="tq",
48
+ textcolor1="white",
49
+ gatecolor2="guo",
50
+ textcolor2="black",
51
+ *args,
52
+ **kwargs,
53
+ ) -> str:
41
54
  result = ""
42
55
 
43
56
  colors = [{"name": "tq", "rgb": (0.03137254901960784, 0.1607843137254902, 0.23921568627450981)}]
@@ -80,34 +93,34 @@ def export_to_qpic(circuit, filename=None, filepath=None, always_use_generators=
80
93
  # generator decomposition of H is misleading
81
94
  if g.name in ["H", "h"]:
82
95
  for target in g.target:
83
- result += " a{qubit} G:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(qubit=target, gcol=gcol,
84
- tcol="{" + tcol + "}", op="H")
96
+ result += " a{qubit} G:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(
97
+ qubit=target, gcol=gcol, tcol="{" + tcol + "}", op="H"
98
+ )
85
99
  if g.is_controlled():
86
100
  for c in g.control:
87
101
  result += names[c] + " "
88
102
  elif always_use_generators and g.make_generator(include_controls=decompose_control_generators) is not None:
89
103
  for ps in g.make_generator(include_controls=decompose_control_generators).paulistrings:
90
- if len(ps) == 0: continue
104
+ if len(ps) == 0:
105
+ continue
91
106
 
92
107
  # if controls are not decomposed this will become a mess
93
108
  # so we will represent NOT gates as + (and not as X)
94
109
  # and will use standard notation for Y and H
95
110
  if not decompose_control_generators and g.name.upper() in ["X", "Y", "Z", "H"]:
96
111
  if g.name.upper() == "X":
97
- result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(qubit=g.target[0],
98
- gcol=gcol,
99
- tcol="{" + tcol + "}",
100
- op="+")
112
+ result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(
113
+ qubit=g.target[0], gcol=gcol, tcol="{" + tcol + "}", op="+"
114
+ )
101
115
  else:
102
- result += " a{qubit} G:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(qubit=g.target[0],
103
- gcol=gcol,
104
- tcol="{" + tcol + "}",
105
- op=g.name.upper())
116
+ result += " a{qubit} G:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(
117
+ qubit=g.target[0], gcol=gcol, tcol="{" + tcol + "}", op=g.name.upper()
118
+ )
106
119
  else:
107
120
  for k, v in ps.items():
108
- result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(qubit=k, gcol=gcol,
109
- tcol="{" + tcol + "}",
110
- op=v.upper())
121
+ result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(
122
+ qubit=k, gcol=gcol, tcol="{" + tcol + "}", op=v.upper()
123
+ )
111
124
  if g.is_controlled() and not decompose_control_generators:
112
125
  for c in g.control:
113
126
  result += names[c] + " "
@@ -121,11 +134,12 @@ def export_to_qpic(circuit, filename=None, filepath=None, always_use_generators=
121
134
  if g.name.upper() in ["Exp-Pauli".upper(), "GenRot".upper()]:
122
135
  # represent ExpPaulis as generators
123
136
  for ps in g.generator.paulistrings:
124
- if len(ps) == 0: continue
137
+ if len(ps) == 0:
138
+ continue
125
139
  for k, v in ps.items():
126
- result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(qubit=k, gcol=gcol,
127
- tcol="{" + tcol + "}",
128
- op=v.upper())
140
+ result += " a{qubit} P:fill={gcol} \\textcolor{tcol}{{{op}}} ".format(
141
+ qubit=k, gcol=gcol, tcol="{" + tcol + "}", op=v.upper()
142
+ )
129
143
  if g.is_controlled():
130
144
  for c in g.control:
131
145
  result += names[c] + " "
@@ -133,12 +147,12 @@ def export_to_qpic(circuit, filename=None, filepath=None, always_use_generators=
133
147
  else:
134
148
  for t in g.target:
135
149
  result += names[t] + " G:fill={gcol} ".format(gcol=gcol)
136
- gname=g.name
150
+ gname = g.name
137
151
  if "R" in gname.upper():
138
- gname=gname.replace("R", "R_")
152
+ gname = gname.replace("R", "R_")
139
153
 
140
154
  if param is not None:
141
- gname="{{{x}}}({angle})".format(x=gname, angle=assign_name(g.parameter))
155
+ gname = "{{{x}}}({angle})".format(x=gname, angle=assign_name(g.parameter))
142
156
 
143
157
  result += "\\textcolor{tcol}{{${op}$}} ".format(tcol="{" + tcol + "}", op=gname)
144
158
  if hasattr(g, "parameter") and g.parameter is not None:
@@ -161,10 +175,7 @@ def export_to_qpic(circuit, filename=None, filepath=None, always_use_generators=
161
175
  return result
162
176
 
163
177
 
164
- def export_to(circuit,
165
- filename: str,
166
- style="tequila",
167
- qubit_names: list = None, *args, **kwargs):
178
+ def export_to(circuit, filename: str, style="tequila", qubit_names: list = None, *args, **kwargs):
168
179
  """
169
180
  Parameters
170
181
  ----------
@@ -193,46 +204,40 @@ def export_to(circuit,
193
204
 
194
205
  if style is None or style == "tequila":
195
206
  style = {
196
- 'decompose_control_generators': False,
197
- 'always_use_generators': True,
198
- 'group_together': False,
199
- 'textcolor1': "white",
207
+ "decompose_control_generators": False,
208
+ "always_use_generators": True,
209
+ "group_together": False,
210
+ "textcolor1": "white",
200
211
  "textcolor2": "black",
201
212
  "gatecolor1": "tq",
202
- "gatecolor2": "guo"
213
+ "gatecolor2": "guo",
203
214
  }
204
215
  elif style == "standard":
205
- style = {
206
- 'decompose_control_generators': False,
207
- 'always_use_generators': False,
208
- 'group_together': False
209
- }
216
+ style = {"decompose_control_generators": False, "always_use_generators": False, "group_together": False}
210
217
  elif style == "plain":
211
218
  # standard without colors
212
219
  style = {
213
- 'decompose_control_generators': False,
214
- 'always_use_generators': False,
215
- 'group_together': False,
216
- 'textcolor1': "black",
220
+ "decompose_control_generators": False,
221
+ "always_use_generators": False,
222
+ "group_together": False,
223
+ "textcolor1": "black",
217
224
  "textcolor2": "black",
218
225
  "gatecolor1": "white",
219
- "gatecolor2": "white"
226
+ "gatecolor2": "white",
220
227
  }
221
228
  elif style == "generators":
222
- style = {
223
- 'decompose_control_generators': True,
224
- 'always_use_generators': True,
225
- 'group_together': "BARRIER"
226
- }
229
+ style = {"decompose_control_generators": True, "always_use_generators": True, "group_together": "BARRIER"}
227
230
  elif not hasattr(style, "items"):
228
231
  raise Exception(
229
232
  "style needs to be `tequila`, or `standard` or `generators` or a dictionary, you gave: {}".format(
230
- str(style)))
233
+ str(style)
234
+ )
235
+ )
231
236
 
232
237
  pop = []
233
- for k,v in kwargs.items():
238
+ for k, v in kwargs.items():
234
239
  if k in style:
235
- style[k]=kwargs[k]
240
+ style[k] = kwargs[k]
236
241
  pop.append(k)
237
242
  for k in pop:
238
243
  kwargs.pop(k)
@@ -253,9 +258,6 @@ def export_to(circuit,
253
258
  if filename[0] == "/":
254
259
  fpath = "/" + fpath
255
260
 
256
- export_to_qpic(circuit=circuit,
257
- filename=fname,
258
- filepath=fpath,
259
- qubit_names=qubit_names, **style, **kwargs)
261
+ export_to_qpic(circuit=circuit, filename=fname, filepath=fpath, qubit_names=qubit_names, **style, **kwargs)
260
262
  if ftype != "qpic":
261
- subprocess.call(["qpic", "{}.qpic".format(fname), "-f", ftype], cwd=fpath)
263
+ subprocess.call(["qpic", "{}.qpic".format(fname), "-f", ftype], cwd=fpath, stdout=subprocess.DEVNULL)