tequila-basic 1.9.8__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 +177 -88
- 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 +91 -56
- 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 +394 -203
- tequila/quantumchemistry/encodings.py +121 -13
- tequila/quantumchemistry/madness_interface.py +170 -96
- tequila/quantumchemistry/orbital_optimizer.py +86 -40
- 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 +258 -106
- tequila/simulators/simulator_aqt.py +102 -0
- tequila/simulators/simulator_base.py +156 -55
- 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 +124 -114
- tequila/simulators/simulator_qlm.py +52 -26
- tequila/simulators/simulator_qulacs.py +85 -59
- tequila/simulators/simulator_spex.py +464 -0
- tequila/simulators/simulator_symbolic.py +6 -5
- tequila/simulators/test_spex_simulator.py +208 -0
- tequila/tools/convenience.py +4 -4
- tequila/tools/qng.py +72 -64
- tequila/tools/random_generators.py +38 -34
- tequila/utils/bitstrings.py +13 -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 +52 -30
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +23 -17
- tequila_basic-1.9.10.dist-info/RECORD +93 -0
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
- tequila_basic-1.9.8.dist-info/RECORD +0 -86
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info/licenses}/LICENSE +0 -0
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
tequila/circuit/circuit.py
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from tequila.circuit._gates_impl import QGateImpl, assign_variable, list_assignment
|
2
|
+
from tequila.circuit._gates_impl import QGateImpl, assign_variable, list_assignment, GlobalPhaseGateImpl, PhaseGateImpl
|
3
3
|
from tequila.utils.exceptions import TequilaException, TequilaWarning
|
4
4
|
from tequila.utils.bitstrings import BitNumbering
|
5
5
|
import typing
|
6
6
|
import copy
|
7
7
|
from collections import defaultdict
|
8
|
+
import numpy as np
|
8
9
|
import warnings
|
9
10
|
|
10
11
|
from .qpic import export_to
|
11
12
|
|
12
|
-
|
13
|
+
|
14
|
+
class QCircuit:
|
13
15
|
"""
|
14
16
|
Fundamental class representing an abstract circuit.
|
15
17
|
|
@@ -65,7 +67,6 @@ class QCircuit():
|
|
65
67
|
spots = [table[q] for q in qus]
|
66
68
|
|
67
69
|
if max(spots) == len(moms):
|
68
|
-
|
69
70
|
moms.append(Moment([g]))
|
70
71
|
else:
|
71
72
|
moms[max(spots)].add_gate(g)
|
@@ -91,8 +92,8 @@ class QCircuit():
|
|
91
92
|
for g in self.gates:
|
92
93
|
p = 0
|
93
94
|
qus = g.qubits
|
94
|
-
if g.
|
95
|
-
if hasattr(g.parameter,
|
95
|
+
if g.is_parameterized():
|
96
|
+
if hasattr(g.parameter, "extract_variables"):
|
96
97
|
p = 1
|
97
98
|
|
98
99
|
if p == 0:
|
@@ -149,6 +150,10 @@ class QCircuit():
|
|
149
150
|
else:
|
150
151
|
return self._gates
|
151
152
|
|
153
|
+
@gates.setter
|
154
|
+
def gates(self, other):
|
155
|
+
self._gates = list(other)
|
156
|
+
|
152
157
|
@property
|
153
158
|
def numbering(self) -> BitNumbering:
|
154
159
|
return BitNumbering.LSB
|
@@ -169,9 +174,11 @@ class QCircuit():
|
|
169
174
|
self._min_n_qubits = other
|
170
175
|
if other < self.max_qubit() + 1:
|
171
176
|
raise TequilaException(
|
172
|
-
"You are trying to set n_qubits to "
|
173
|
-
|
174
|
-
|
177
|
+
"You are trying to set n_qubits to "
|
178
|
+
+ str(other)
|
179
|
+
+ " but your circuit needs at least: "
|
180
|
+
+ str(self.max_qubit() + 1)
|
181
|
+
)
|
175
182
|
return self
|
176
183
|
|
177
184
|
def __init__(self, gates=None, parameter_map=None):
|
@@ -209,7 +216,7 @@ class QCircuit():
|
|
209
216
|
"""
|
210
217
|
parameter_map = defaultdict(list)
|
211
218
|
for idx, gate in enumerate(self.gates):
|
212
|
-
if gate.
|
219
|
+
if gate.is_parameterized():
|
213
220
|
variables = gate.extract_variables()
|
214
221
|
for variable in variables:
|
215
222
|
parameter_map[variable] += [(idx, gate)]
|
@@ -254,8 +261,8 @@ class QCircuit():
|
|
254
261
|
the gates to add at the corresponding positions
|
255
262
|
replace: list of bool: (Default value: None)
|
256
263
|
Default is None which corresponds to all true
|
257
|
-
decide if gates shall be
|
258
|
-
if replace[i] = true: gate at position [i] will be
|
264
|
+
decide if gates shall be replaced or if the new parts shall be inserted without replacement
|
265
|
+
if replace[i] = true: gate at position [i] will be replaced by gates[i]
|
259
266
|
if replace[i] = false: gates[i] circuit will be inserted at position [i] (beaming before gate previously at position [i])
|
260
267
|
Returns
|
261
268
|
-------
|
@@ -271,10 +278,10 @@ class QCircuit():
|
|
271
278
|
dataset = zip(positions, circuits, replace)
|
272
279
|
dataset = sorted(dataset, key=lambda x: x[0])
|
273
280
|
|
274
|
-
|
275
|
-
|
276
|
-
for idx, circuit, do_replace in dataset:
|
281
|
+
new_gatelist = []
|
282
|
+
last_idx = -1
|
277
283
|
|
284
|
+
for idx, circuit, do_replace in dataset:
|
278
285
|
# failsafe
|
279
286
|
if hasattr(circuit, "gates"):
|
280
287
|
gatelist = circuit.gates
|
@@ -283,13 +290,14 @@ class QCircuit():
|
|
283
290
|
else:
|
284
291
|
gatelist = [circuit]
|
285
292
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
+
new_gatelist += self.gates[last_idx + 1 : idx]
|
294
|
+
new_gatelist += gatelist
|
295
|
+
if not do_replace:
|
296
|
+
new_gatelist.append(self.gates[idx])
|
297
|
+
|
298
|
+
last_idx = idx
|
299
|
+
|
300
|
+
new_gatelist += self.gates[last_idx + 1 :]
|
293
301
|
|
294
302
|
result = QCircuit(gates=new_gatelist)
|
295
303
|
result.n_qubits = max(result.n_qubits, self.n_qubits)
|
@@ -344,11 +352,11 @@ class QCircuit():
|
|
344
352
|
whether or not all gates in the circuit are paremtrized
|
345
353
|
"""
|
346
354
|
for gate in self.gates:
|
347
|
-
if not gate.
|
355
|
+
if not gate.is_parameterized():
|
348
356
|
return False
|
349
357
|
else:
|
350
|
-
if hasattr(gate,
|
351
|
-
if not hasattr(gate.parameter,
|
358
|
+
if hasattr(gate, "parameter"):
|
359
|
+
if not hasattr(gate.parameter, "wrap"):
|
352
360
|
return False
|
353
361
|
else:
|
354
362
|
continue
|
@@ -364,11 +372,11 @@ class QCircuit():
|
|
364
372
|
whether or not all gates in the circuit are unparametrized
|
365
373
|
"""
|
366
374
|
for gate in self.gates:
|
367
|
-
if not gate.
|
375
|
+
if not gate.is_parameterized():
|
368
376
|
continue
|
369
377
|
else:
|
370
|
-
if hasattr(gate,
|
371
|
-
if not hasattr(gate.parameter,
|
378
|
+
if hasattr(gate, "parameter"):
|
379
|
+
if not hasattr(gate.parameter, "wrap"):
|
372
380
|
continue
|
373
381
|
else:
|
374
382
|
return False
|
@@ -386,7 +394,7 @@ class QCircuit():
|
|
386
394
|
for k, v in other._parameter_map.items():
|
387
395
|
self._parameter_map[k] += [(x[0] + offset, x[1]) for x in v]
|
388
396
|
|
389
|
-
self._gates +=
|
397
|
+
self._gates += other.gates
|
390
398
|
self._min_n_qubits = max(self._min_n_qubits, other._min_n_qubits)
|
391
399
|
|
392
400
|
return self
|
@@ -438,6 +446,76 @@ class QCircuit():
|
|
438
446
|
else:
|
439
447
|
return QCircuit(gates=[gate])
|
440
448
|
|
449
|
+
def to_matrix(self, variables=None):
|
450
|
+
"""
|
451
|
+
take the circuit and return the unitary matrix corresponding to it.
|
452
|
+
Parameters
|
453
|
+
----------
|
454
|
+
variables: dict:
|
455
|
+
(Default value = None)
|
456
|
+
a dictionary mapping variable names to values. If None, the circuit must not contain any variables.
|
457
|
+
If the circuit contains variables, they must be provided here.
|
458
|
+
|
459
|
+
Returns
|
460
|
+
-------
|
461
|
+
np.ndarray:
|
462
|
+
the unitary matrix corresponding to the circuit.
|
463
|
+
"""
|
464
|
+
import quimb.gates
|
465
|
+
import quimb.tensor as qtn
|
466
|
+
from tequila import compile_circuit
|
467
|
+
|
468
|
+
num_variables = len(self.extract_variables())
|
469
|
+
|
470
|
+
if num_variables == 0:
|
471
|
+
variables = {}
|
472
|
+
elif variables is None:
|
473
|
+
raise TequilaException(
|
474
|
+
f"QCircuit.to_matrix(): no variables provided, but the circuit has {num_variables} variables"
|
475
|
+
)
|
476
|
+
|
477
|
+
compiled_circuit = compile_circuit(
|
478
|
+
self,
|
479
|
+
)
|
480
|
+
compiled_circuit = compiled_circuit.map_variables(variables)
|
481
|
+
|
482
|
+
gate_mapping = {"Rx": "RX", "Ry": "RY", "Rz": "RZ", "H": "H", "X": "X"}
|
483
|
+
|
484
|
+
quimb_circuit = qtn.Circuit(self.n_qubits)
|
485
|
+
|
486
|
+
# quimb uses MSB convention, so we need to modify the qubit indices
|
487
|
+
# to LSB
|
488
|
+
for g in compiled_circuit.gates:
|
489
|
+
if g.name not in gate_mapping:
|
490
|
+
raise TequilaException(
|
491
|
+
f"Gate {g.name} is not supported for conversion to matrix. "
|
492
|
+
f"Supported gates: {list(gate_mapping.keys())}"
|
493
|
+
)
|
494
|
+
|
495
|
+
if g.is_parameterized():
|
496
|
+
quimb_circuit.apply_gate(
|
497
|
+
gate_mapping[g.name],
|
498
|
+
params=[float(g.parameter())],
|
499
|
+
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
500
|
+
parameterize=True,
|
501
|
+
)
|
502
|
+
elif g.is_controlled():
|
503
|
+
quimb_circuit.apply_gate(
|
504
|
+
gate_mapping[g.name],
|
505
|
+
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
506
|
+
controls=[abs(c - self.n_qubits + 1) for c in list(g.control)],
|
507
|
+
)
|
508
|
+
else:
|
509
|
+
quimb_circuit.apply_gate(
|
510
|
+
gate_mapping[g.name],
|
511
|
+
qubits=[abs(t - self.n_qubits + 1) for t in list(g.target)],
|
512
|
+
)
|
513
|
+
|
514
|
+
uni = quimb_circuit.get_uni()
|
515
|
+
unitary = np.array(uni.to_dense())
|
516
|
+
|
517
|
+
return unitary
|
518
|
+
|
441
519
|
def to_networkx(self):
|
442
520
|
"""
|
443
521
|
Turn a given quantum circuit from tequila into graph form via NetworkX
|
@@ -446,6 +524,7 @@ class QCircuit():
|
|
446
524
|
"""
|
447
525
|
# avoiding dependcies (only used here so far)
|
448
526
|
import networkx as nx
|
527
|
+
|
449
528
|
G = nx.Graph()
|
450
529
|
for q in self.qubits:
|
451
530
|
G.add_node(q)
|
@@ -454,20 +533,20 @@ class QCircuit():
|
|
454
533
|
if gate.control:
|
455
534
|
for s in gate.control:
|
456
535
|
for t in gate.target:
|
457
|
-
tstr =
|
536
|
+
tstr = ""
|
458
537
|
tstr += str(t)
|
459
538
|
target = int(tstr)
|
460
539
|
Gdict[s].append(target) # add target to key of correlated controls
|
461
540
|
for p in gate.target:
|
462
541
|
for r in gate.control:
|
463
|
-
cstr =
|
542
|
+
cstr = ""
|
464
543
|
cstr += str(r)
|
465
544
|
control = int(cstr)
|
466
545
|
Gdict[p].append(control) # add control to key of correlated targets
|
467
546
|
else:
|
468
547
|
for s in gate.target:
|
469
548
|
for t in gate.target:
|
470
|
-
tstr2 =
|
549
|
+
tstr2 = ""
|
471
550
|
tstr2 += str(t)
|
472
551
|
target2 = int(tstr2)
|
473
552
|
Gdict[s].append(target2)
|
@@ -476,8 +555,9 @@ class QCircuit():
|
|
476
555
|
for q in b:
|
477
556
|
lConn.append((a, q))
|
478
557
|
G.add_edges_from(lConn)
|
479
|
-
GPaths = list(
|
480
|
-
G)
|
558
|
+
GPaths = list(
|
559
|
+
nx.connected_components(G)
|
560
|
+
) # connections of various qubits, excluding repetitions (ex- (1,3) instead of (1,3) and (3,1))
|
481
561
|
GIso = [g for g in GPaths if len(g) == 1] # list of Isolated qubits
|
482
562
|
return G
|
483
563
|
|
@@ -508,7 +588,10 @@ class QCircuit():
|
|
508
588
|
whether or not the circuit is properly constructed.
|
509
589
|
|
510
590
|
"""
|
511
|
-
for
|
591
|
+
for (
|
592
|
+
k,
|
593
|
+
v,
|
594
|
+
) in self._parameter_map.items():
|
512
595
|
test = [self.gates[x[0]] == x[1] for x in v]
|
513
596
|
test += [k in self._gates[x[0]].extract_variables() for x in v]
|
514
597
|
return all(test)
|
@@ -533,8 +616,7 @@ class QCircuit():
|
|
533
616
|
# currently its recreated in the init function
|
534
617
|
return QCircuit(gates=new_gates)
|
535
618
|
|
536
|
-
def add_controls(self, control, inpl: typing.Optional[bool] = False)
|
537
|
-
-> typing.Optional[QCircuit]:
|
619
|
+
def add_controls(self, control, inpl: typing.Optional[bool] = False) -> typing.Optional[QCircuit]:
|
538
620
|
"""Depending on the truth value of inpl:
|
539
621
|
- return controlled version of self with control as the control qubits if inpl;
|
540
622
|
- mutate self so that the qubits in control are added as the control qubits if not inpl.
|
@@ -570,8 +652,9 @@ class QCircuit():
|
|
570
652
|
if len(control_lst) < len(gate.control) + len(control):
|
571
653
|
# warnings.warn("Some of the controls {} were already included in the control "
|
572
654
|
# "of a gate {}.".format(control, gate), TequilaWarning)
|
573
|
-
raise TequilaWarning(
|
574
|
-
|
655
|
+
raise TequilaWarning(
|
656
|
+
f"Some of the controls {control} were already included in the control of a gate {gate}."
|
657
|
+
)
|
575
658
|
else:
|
576
659
|
control_lst, not_control = list(control), list()
|
577
660
|
|
@@ -579,8 +662,9 @@ class QCircuit():
|
|
579
662
|
if any(qubit in control for qubit in not_control):
|
580
663
|
# warnings.warn("The target and control {} were the same qubit for a gate {}."
|
581
664
|
# .format(control, gate), TequilaWarning)
|
582
|
-
raise TequilaWarning(
|
583
|
-
|
665
|
+
raise TequilaWarning(
|
666
|
+
f"The target for a gate {gate} and the control list {control_lst} had a common qubit."
|
667
|
+
)
|
584
668
|
|
585
669
|
cgate._control = tuple(control_lst)
|
586
670
|
cgate.finalize()
|
@@ -593,25 +677,33 @@ class QCircuit():
|
|
593
677
|
|
594
678
|
This is an in-place method, so it mutates self and doesn't return any value.
|
595
679
|
|
596
|
-
Raise TequilaWarning if there any qubits in common between self and control.
|
680
|
+
Raise TequilaWarning if there are any qubits in common between self and control.
|
597
681
|
"""
|
598
682
|
gates = self.gates
|
599
683
|
control = list_assignment(control)
|
600
684
|
|
601
|
-
for gate in gates:
|
602
|
-
if gate
|
685
|
+
for i, gate in enumerate(gates):
|
686
|
+
if isinstance(gate, GlobalPhaseGateImpl):
|
687
|
+
gate = PhaseGateImpl(phase=gate.parameter, target=control[0])
|
688
|
+
gates[i] = gate
|
689
|
+
not_control = []
|
690
|
+
control_lst = list(control[1:])
|
691
|
+
elif gate.is_controlled():
|
603
692
|
control_lst = list(set(list(gate.control) + list(control)))
|
604
693
|
|
605
694
|
# Need to check duplicates
|
606
|
-
not_control = list(set(qubit for qubit in list(gate.qubits)
|
607
|
-
if qubit not in list(gate.control)))
|
695
|
+
not_control = list(set(qubit for qubit in list(gate.qubits) if qubit not in list(gate.control)))
|
608
696
|
|
609
697
|
# Raise TequilaWarning if control qubit is duplicated
|
610
698
|
if len(control_lst) < len(gate.control) + len(control):
|
611
699
|
# warnings.warn("Some of the controls {} were already included in the control "
|
612
700
|
# "of a gate {}.".format(control, gate), TequilaWarning)
|
613
|
-
raise TequilaWarning(
|
614
|
-
|
701
|
+
raise TequilaWarning(
|
702
|
+
f"Some of the controls {control} were already included "
|
703
|
+
f"in the control of a gate {gate}. "
|
704
|
+
f"This might be because the same instance of a gate is used in multiple places, "
|
705
|
+
f"e.g. because the same circuit was appended twice."
|
706
|
+
)
|
615
707
|
else:
|
616
708
|
control_lst, not_control = list(control), list()
|
617
709
|
|
@@ -619,8 +711,7 @@ class QCircuit():
|
|
619
711
|
if any(qubit in control for qubit in not_control):
|
620
712
|
# warnings.warn("The target and control {} were the same qubit for a gate {}."
|
621
713
|
# .format(control, gate), TequilaWarning)
|
622
|
-
raise TequilaWarning(f
|
623
|
-
f'and the control list {control} had a common qubit.')
|
714
|
+
raise TequilaWarning(f"The target for a gate {gate} and the control list {control} had a common qubit.")
|
624
715
|
|
625
716
|
gate._control = tuple(control_lst)
|
626
717
|
gate.finalize()
|
@@ -645,9 +736,9 @@ class QCircuit():
|
|
645
736
|
for k, v in variables.items():
|
646
737
|
if k not in my_variables:
|
647
738
|
warnings.warn(
|
648
|
-
"map_variables: variable {} is not part of circuit with variables {}".format(k,
|
649
|
-
|
650
|
-
|
739
|
+
"map_variables: variable {} is not part of circuit with variables {}".format(k, my_variables),
|
740
|
+
TequilaWarning,
|
741
|
+
)
|
651
742
|
|
652
743
|
new_gates = [copy.deepcopy(gate).map_variables(variables) for gate in self.gates]
|
653
744
|
|
@@ -683,11 +774,11 @@ class Moment(QCircuit):
|
|
683
774
|
mu = []
|
684
775
|
mp = []
|
685
776
|
for gate in self.gates:
|
686
|
-
if not gate.
|
777
|
+
if not gate.is_parameterized():
|
687
778
|
mu.append(gate)
|
688
779
|
else:
|
689
|
-
if hasattr(gate,
|
690
|
-
if not hasattr(gate.parameter,
|
780
|
+
if hasattr(gate, "parameter"):
|
781
|
+
if not hasattr(gate.parameter, "wrap"):
|
691
782
|
mu.append(gate)
|
692
783
|
else:
|
693
784
|
mp.append(gate)
|
@@ -720,8 +811,8 @@ class Moment(QCircuit):
|
|
720
811
|
for q in g.qubits:
|
721
812
|
if q in occ:
|
722
813
|
raise TequilaException(
|
723
|
-
|
724
|
-
|
814
|
+
"cannot have doubly occupied qubits, which occurred at qubit {}".format(str(q))
|
815
|
+
)
|
725
816
|
else:
|
726
817
|
occ.append(q)
|
727
818
|
if sort:
|
@@ -782,8 +873,7 @@ class Moment(QCircuit):
|
|
782
873
|
if q not in first_overlap:
|
783
874
|
first_overlap.append(q)
|
784
875
|
else:
|
785
|
-
raise TequilaException(
|
786
|
-
'cannot have a moment with multiple operations acting on the same qubit!')
|
876
|
+
raise TequilaException("cannot have a moment with multiple operations acting on the same qubit!")
|
787
877
|
|
788
878
|
new = self.with_gate(gl[0])
|
789
879
|
for g in gl[1:]:
|
@@ -810,8 +900,8 @@ class Moment(QCircuit):
|
|
810
900
|
for n in newq:
|
811
901
|
if n in prev:
|
812
902
|
raise TequilaException(
|
813
|
-
|
814
|
-
|
903
|
+
"cannot add gate {} to moment; qubit {} already occupied.".format(str(gate), str(n))
|
904
|
+
)
|
815
905
|
|
816
906
|
self._gates.append(gate)
|
817
907
|
self.sort_gates()
|
@@ -832,17 +922,17 @@ class Moment(QCircuit):
|
|
832
922
|
QCircuit or Moment:
|
833
923
|
self, with unwanted gate removed and new gates inserted. May not be a moment.
|
834
924
|
"""
|
835
|
-
if hasattr(gates,
|
925
|
+
if hasattr(gates, "__iter__"):
|
836
926
|
gs = gates
|
837
927
|
else:
|
838
928
|
gs = [gates]
|
839
929
|
|
840
930
|
new = self.gates[:position]
|
841
931
|
new.extend(gs)
|
842
|
-
new.extend(self.gates[(position + 1):])
|
932
|
+
new.extend(self.gates[(position + 1) :])
|
843
933
|
try:
|
844
934
|
return Moment(gates=new)
|
845
|
-
except:
|
935
|
+
except Exception:
|
846
936
|
return QCircuit(gates=new)
|
847
937
|
|
848
938
|
def as_circuit(self):
|
@@ -864,11 +954,11 @@ class Moment(QCircuit):
|
|
864
954
|
whether or not EVERY gate in self.gates is parameterized.
|
865
955
|
"""
|
866
956
|
for gate in self.gates:
|
867
|
-
if not gate.
|
957
|
+
if not gate.is_parameterized():
|
868
958
|
return False
|
869
959
|
else:
|
870
|
-
if hasattr(gate,
|
871
|
-
if not hasattr(gate.parameter,
|
960
|
+
if hasattr(gate, "parameter"):
|
961
|
+
if not hasattr(gate.parameter, "wrap"):
|
872
962
|
return False
|
873
963
|
else:
|
874
964
|
continue
|
@@ -883,7 +973,6 @@ class Moment(QCircuit):
|
|
883
973
|
return result
|
884
974
|
|
885
975
|
def __iadd__(self, other):
|
886
|
-
|
887
976
|
new = self.as_circuit()
|
888
977
|
if isinstance(other, QGateImpl):
|
889
978
|
other = new.wrap_gate(other)
|
@@ -918,24 +1007,24 @@ class Moment(QCircuit):
|
|
918
1007
|
try:
|
919
1008
|
result = self.add_gate(other.gates[0])
|
920
1009
|
result._min_n_qubits += len(other.qubits)
|
921
|
-
except:
|
1010
|
+
except Exception:
|
922
1011
|
result = self.as_circuit() + QCircuit.wrap_gate(other)
|
923
|
-
result._min_n_qubits = max(self.as_circuit()._min_n_qubits,
|
924
|
-
QCircuit.wrap_gate(other)._min_n_qubits)
|
1012
|
+
result._min_n_qubits = max(self.as_circuit()._min_n_qubits, QCircuit.wrap_gate(other)._min_n_qubits)
|
925
1013
|
|
926
1014
|
else:
|
927
1015
|
if isinstance(other, QGateImpl):
|
928
1016
|
try:
|
929
1017
|
result = self.add_gate(other)
|
930
1018
|
result._min_n_qubits += len(other.qubits)
|
931
|
-
except:
|
1019
|
+
except Exception:
|
932
1020
|
result = self.as_circuit() + QCircuit.wrap_gate(other)
|
933
|
-
result._min_n_qubits = max(self.as_circuit()._min_n_qubits,
|
934
|
-
QCircuit.wrap_gate(other)._min_n_qubits)
|
1021
|
+
result._min_n_qubits = max(self.as_circuit()._min_n_qubits, QCircuit.wrap_gate(other)._min_n_qubits)
|
935
1022
|
else:
|
936
1023
|
raise TequilaException(
|
937
|
-
|
938
|
-
str(type(other))
|
1024
|
+
"cannot add moments to types other than QCircuit,Moment,or Gate; recieved summand of type {}".format(
|
1025
|
+
str(type(other))
|
1026
|
+
)
|
1027
|
+
)
|
939
1028
|
return result
|
940
1029
|
|
941
1030
|
@staticmethod
|
@@ -964,36 +1053,36 @@ class Moment(QCircuit):
|
|
964
1053
|
TequilaException
|
965
1054
|
"""
|
966
1055
|
raise TequilaException(
|
967
|
-
|
968
|
-
|
1056
|
+
"this method should never be called from Moment. Call from the QCircuit class itself instead."
|
1057
|
+
)
|
969
1058
|
|
970
1059
|
|
971
|
-
def find_unused_qubit(U0: QCircuit = None, U1: QCircuit = None)->int:
|
972
|
-
|
973
|
-
Function that checks which are the active qubits of two circuits and
|
1060
|
+
def find_unused_qubit(U0: QCircuit = None, U1: QCircuit = None) -> int:
|
1061
|
+
"""
|
1062
|
+
Function that checks which are the active qubits of two circuits and
|
974
1063
|
provides an unused qubit that is not among them. If all qubits are used
|
975
1064
|
it adds a new one.
|
976
1065
|
|
977
1066
|
Parameters
|
978
1067
|
----------
|
979
1068
|
U0 : QCircuit, corresponding to the first state.
|
980
|
-
|
1069
|
+
|
981
1070
|
U1 : QCircuit, corresponding to the second state.
|
982
1071
|
|
983
1072
|
Returns
|
984
1073
|
-------
|
985
1074
|
control_qubit : int
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
active_qubits = list(set(U0.qubits+U1.qubits))
|
1075
|
+
|
1076
|
+
"""
|
1077
|
+
|
1078
|
+
active_qubits = list(set(U0.qubits + U1.qubits))
|
990
1079
|
# default
|
991
1080
|
free_qubit = max(active_qubits) + 1
|
992
1081
|
# see if we can use another one
|
993
|
-
for n in range(max(active_qubits)+1):
|
1082
|
+
for n in range(max(active_qubits) + 1):
|
994
1083
|
if n not in active_qubits:
|
995
1084
|
free_qubit = n
|
996
1085
|
break
|
997
1086
|
assert free_qubit not in active_qubits
|
998
|
-
|
1087
|
+
|
999
1088
|
return free_qubit
|