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.
- tequila/__init__.py +29 -14
- tequila/apps/__init__.py +14 -5
- tequila/apps/_unary_state_prep_impl.py +145 -112
- tequila/apps/adapt/__init__.py +9 -1
- tequila/apps/adapt/adapt.py +154 -113
- tequila/apps/krylov/__init__.py +1 -1
- tequila/apps/krylov/krylov.py +23 -21
- tequila/apps/robustness/helpers.py +10 -6
- tequila/apps/robustness/interval.py +238 -156
- tequila/apps/unary_state_prep.py +29 -23
- tequila/autograd_imports.py +8 -5
- tequila/circuit/__init__.py +2 -1
- tequila/circuit/_gates_impl.py +135 -67
- tequila/circuit/circuit.py +163 -79
- tequila/circuit/compiler.py +114 -105
- tequila/circuit/gates.py +288 -120
- tequila/circuit/gradient.py +35 -23
- tequila/circuit/noise.py +83 -74
- tequila/circuit/postselection.py +120 -0
- tequila/circuit/pyzx.py +10 -6
- tequila/circuit/qasm.py +201 -83
- tequila/circuit/qpic.py +63 -61
- tequila/grouping/binary_rep.py +148 -146
- tequila/grouping/binary_utils.py +84 -75
- tequila/grouping/compile_groups.py +334 -230
- tequila/grouping/ev_utils.py +77 -41
- tequila/grouping/fermionic_functions.py +383 -308
- tequila/grouping/fermionic_methods.py +170 -123
- tequila/grouping/overlapping_methods.py +69 -52
- tequila/hamiltonian/paulis.py +12 -13
- tequila/hamiltonian/paulistring.py +1 -1
- tequila/hamiltonian/qubit_hamiltonian.py +45 -35
- tequila/ml/__init__.py +1 -0
- tequila/ml/interface_torch.py +19 -16
- tequila/ml/ml_api.py +11 -10
- tequila/ml/utils_ml.py +12 -11
- tequila/objective/__init__.py +8 -3
- tequila/objective/braket.py +55 -47
- tequila/objective/objective.py +87 -55
- tequila/objective/qtensor.py +36 -27
- tequila/optimizers/__init__.py +31 -23
- tequila/optimizers/_containers.py +11 -7
- tequila/optimizers/optimizer_base.py +111 -83
- tequila/optimizers/optimizer_gd.py +258 -231
- tequila/optimizers/optimizer_gpyopt.py +56 -42
- tequila/optimizers/optimizer_scipy.py +157 -112
- tequila/quantumchemistry/__init__.py +66 -38
- tequila/quantumchemistry/chemistry_tools.py +393 -209
- tequila/quantumchemistry/encodings.py +121 -13
- tequila/quantumchemistry/madness_interface.py +170 -96
- tequila/quantumchemistry/orbital_optimizer.py +86 -41
- tequila/quantumchemistry/psi4_interface.py +166 -97
- tequila/quantumchemistry/pyscf_interface.py +70 -23
- tequila/quantumchemistry/qc_base.py +866 -414
- tequila/simulators/__init__.py +0 -3
- tequila/simulators/simulator_api.py +247 -105
- tequila/simulators/simulator_aqt.py +102 -0
- tequila/simulators/simulator_base.py +147 -53
- tequila/simulators/simulator_cirq.py +58 -42
- tequila/simulators/simulator_cudaq.py +600 -0
- tequila/simulators/simulator_ddsim.py +390 -0
- tequila/simulators/simulator_mqp.py +30 -0
- tequila/simulators/simulator_pyquil.py +190 -171
- tequila/simulators/simulator_qibo.py +95 -87
- tequila/simulators/simulator_qiskit.py +119 -107
- tequila/simulators/simulator_qlm.py +52 -26
- tequila/simulators/simulator_qulacs.py +74 -52
- tequila/simulators/simulator_spex.py +95 -60
- tequila/simulators/simulator_symbolic.py +6 -5
- tequila/simulators/test_spex_simulator.py +8 -11
- tequila/tools/convenience.py +4 -4
- tequila/tools/qng.py +72 -64
- tequila/tools/random_generators.py +38 -34
- tequila/utils/bitstrings.py +7 -7
- tequila/utils/exceptions.py +19 -5
- tequila/utils/joined_transformation.py +8 -10
- tequila/utils/keymap.py +0 -5
- tequila/utils/misc.py +6 -4
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +47 -28
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
- tequila_basic-1.9.10.dist-info/RECORD +93 -0
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
- tequila_basic-1.9.9.dist-info/RECORD +0 -88
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
- {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(
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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 =
|
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 =
|
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]) ->
|
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() ==
|
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
|
332
|
-
name.startswith("
|
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(
|
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(
|
346
|
-
|
347
|
-
|
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(
|
361
|
-
|
362
|
-
|
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(
|
366
|
-
|
367
|
-
|
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(
|
371
|
-
|
372
|
-
|
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(
|
376
|
-
|
377
|
-
|
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(
|
380
|
-
|
381
|
-
|
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(
|
534
|
+
if angle.find("pi") == -1:
|
416
535
|
raise TequilaException("Invalid specification {}".format(name))
|
417
|
-
angle = angle.replace(
|
536
|
+
angle = angle.replace("pi", "")
|
418
537
|
try:
|
419
538
|
sign = 1
|
420
539
|
div = 1
|
421
|
-
if angle.find(
|
422
|
-
angle = angle.replace(
|
540
|
+
if angle.find("-") != -1:
|
541
|
+
angle = angle.replace("-", "")
|
423
542
|
sign = -1
|
424
|
-
if angle.find(
|
425
|
-
div = float(angle[angle.index(
|
426
|
-
angle = angle[:angle.index(
|
427
|
-
if angle.find(
|
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
|
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(
|
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.
|
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(
|
38
|
-
|
39
|
-
|
40
|
-
|
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(
|
84
|
-
|
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:
|
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(
|
98
|
-
|
99
|
-
|
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(
|
103
|
-
|
104
|
-
|
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(
|
109
|
-
|
110
|
-
|
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:
|
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(
|
127
|
-
|
128
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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)
|