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
@@ -0,0 +1,390 @@
1
+ from tequila.simulators.simulator_base import BackendCircuit, QCircuit, BackendExpectationValue
2
+ from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
3
+ from tequila import TequilaException
4
+ from tequila import BitString, BitNumbering
5
+ from tequila.utils.keymap import KeyMapRegisterToSubregister
6
+ from tequila.utils import to_float
7
+ from typing import Union
8
+
9
+ import numpy as np
10
+ from mqt.ddsim.pyddsim import CircuitSimulator
11
+ from mqt.core.ir import QuantumComputation
12
+ from mqt.core.ir.operations import StandardOperation, SymbolicOperation, NonUnitaryOperation, Control, OpType
13
+ from mqt.core.ir.symbolic import Variable, Expression, Term
14
+
15
+ import numbers
16
+ from tequila.circuit.compiler import change_basis
17
+
18
+
19
+ def set_computational_basis(state: int, n_qubits: int) -> QuantumComputation:
20
+ qc = QuantumComputation(n_qubits)
21
+ bitstring = BitString.from_int(state, n_qubits)
22
+ for i, bit in enumerate(bitstring):
23
+ if bit:
24
+ qc.x(i)
25
+ return qc
26
+
27
+
28
+ class TequilaDDSimException(TequilaException):
29
+ def __str__(self):
30
+ return "Error in DDSim backend:" + self.message
31
+
32
+
33
+ class BackendCircuitDDSim(BackendCircuit):
34
+ """
35
+ Class representing circuits compiled to DDSim.
36
+ See BackendCircuit for documentation of features and methods inherited therefrom
37
+
38
+ Attributes
39
+ ----------
40
+ counter:
41
+ counts how many distinct ddsim Variables are employed in the circuit.
42
+ op_lookup: dict:
43
+ dictionary mapping strings (tequila gate names) to ddsim objects (mqt.core.ir).
44
+ resolver:
45
+ dictionary for resolving parameters at runtime for circuits.
46
+ tq_to_ddsim: dict:
47
+ dictionary mapping tequila Variables and Objectives to ddsim Variables, for parameter resolution.
48
+ """
49
+
50
+ numbering = BitNumbering.LSB
51
+
52
+ quantum_state_class = QuantumComputation
53
+
54
+ # TODO: Set to true and use mqt.core.dd to simulate (only supports unitary operations i.e no sampling or reset)
55
+ supports_sampling_initialization = False
56
+ supports_generic_initialization = False
57
+
58
+ def __init__(self, abstract_circuit: QCircuit, variables: dict, *args, **kwargs):
59
+ """
60
+
61
+ Parameters
62
+ ----------
63
+ abstract_circuit: QCircuit:
64
+ the circuit to compile to ddsim
65
+ variables: dict:
66
+ values of all variables in the circuit, to compile with.
67
+ args
68
+ kwargs
69
+ """
70
+ self.op_lookup = {
71
+ "I": OpType.i,
72
+ "X": OpType.x,
73
+ "Y": OpType.y,
74
+ "Z": OpType.z,
75
+ "H": OpType.h,
76
+ "Rx": OpType.rx,
77
+ "Ry": OpType.ry,
78
+ "Rz": OpType.rz,
79
+ "SWAP": OpType.swap,
80
+ }
81
+
82
+ self.counter = 0
83
+ self.tq_to_ddsim = {}
84
+
85
+ self.resolver = None
86
+ qubit_map = {q: i for i, q in enumerate(abstract_circuit.qubits)}
87
+
88
+ super().__init__(abstract_circuit=abstract_circuit, variables=variables, qubit_map=qubit_map, *args, **kwargs)
89
+
90
+ def initialize_state(self, n_qubits: int = None, initial_state: Union[int, QubitWaveFunction] = None):
91
+ if n_qubits is None:
92
+ n_qubits = self.n_qubits
93
+
94
+ state = self.quantum_state_class(n_qubits)
95
+
96
+ if isinstance(initial_state, int):
97
+ state = set_computational_basis(initial_state, n_qubits)
98
+ elif isinstance(initial_state, QubitWaveFunction):
99
+ raise TequilaDDSimException("backend does not support arbitrary initial states")
100
+
101
+ return state
102
+
103
+ def update_variables(self, variables: dict):
104
+ """
105
+ set new variable values for the circuit.
106
+ Parameters
107
+ ----------
108
+ variables: dict:
109
+ the variables to supply to the circuit.
110
+
111
+ Returns
112
+ -------
113
+ None
114
+ """
115
+ if isinstance(variables, dict):
116
+ variables = {k: to_float(v) for k, v in variables.items()}
117
+
118
+ if len(self.tq_to_ddsim.keys()) > 0:
119
+ self.resolver = {k: v(variables) for v, k in self.tq_to_ddsim.items()}
120
+
121
+ def do_simulate(self, variables, initial_state: Union[int, QubitWaveFunction], *args, **kwargs):
122
+ """
123
+ Helper function to perform simulation.
124
+
125
+ Parameters
126
+ ----------
127
+ variables: dict:
128
+ variables to supply to the circuit.
129
+ initial_state:
130
+ information indicating the initial state on which the circuit should act.
131
+ args
132
+ kwargs
133
+
134
+ Returns
135
+ -------
136
+ QubitWaveFunction:
137
+ QubitWaveFunction representing result of the simulation.
138
+ """
139
+ state = self.initialize_state(self.n_qubits, initial_state).to_operation()
140
+ if state is not None:
141
+ self.circuit.insert(idx=0, op=state)
142
+ sim_kwargs = {
143
+ "approximation_step_fidelity": kwargs.get("approximation_step_fidelity", 1),
144
+ "approximation_steps": kwargs.get("approximation_steps", 1),
145
+ "approximation_strategy": kwargs.get("approximation_strategy", "fidelity"),
146
+ "seed": kwargs.get("seed", -1),
147
+ }
148
+ if self.resolver is not None:
149
+ circuit = self.circuit.instantiate(self.resolver)
150
+ else:
151
+ circuit = self.circuit
152
+ sim = CircuitSimulator(circuit, **sim_kwargs)
153
+ sim.simulate(shots=0)
154
+ vec = sim.get_constructed_dd().get_vector()
155
+ wfn = QubitWaveFunction.from_array(array=np.array(vec, copy=False), numbering=self.numbering)
156
+ return wfn
157
+
158
+ def convert_measurements(self, backend_result, target_qubits=None) -> QubitWaveFunction:
159
+ """
160
+ Transform backend evaluation results into QubitWaveFunction
161
+ Parameters
162
+ ----------
163
+ backend_result:
164
+ the return value of backend simulation.
165
+
166
+ Returns
167
+ -------
168
+ QubitWaveFunction
169
+ results transformed to tequila native QubitWaveFunction
170
+ """
171
+ result = QubitWaveFunction(self.n_qubits, self.numbering)
172
+
173
+ for k, v in backend_result.items():
174
+ # ddsim uses LSB bitstrings, but from_binary expects MSB
175
+ converted_key = BitString.from_binary(k[::-1])
176
+ result[converted_key] = v
177
+
178
+ if target_qubits is not None:
179
+ mapped_target = [self.qubit_map[q].number for q in target_qubits]
180
+ mapped_full = [self.qubit_map[q].number for q in self.abstract_qubits]
181
+ keymap = KeyMapRegisterToSubregister(subregister=mapped_target, register=mapped_full)
182
+ result = QubitWaveFunction.from_wavefunction(result, keymap, n_qubits=len(target_qubits))
183
+
184
+ return result
185
+
186
+ def do_sample(self, samples, circuit, read_out_qubits, initial_state=0, *args, **kwargs) -> QubitWaveFunction:
187
+ """
188
+ Helper function for performing sampling.
189
+
190
+ Parameters
191
+ ----------
192
+ samples: int:
193
+ the number of samples to be taken.
194
+ circuit:
195
+ the circuit to sample from.
196
+ initial_state:
197
+ initial state to apply the circuit to.
198
+ args
199
+ kwargs
200
+
201
+ Returns
202
+ -------
203
+ QubitWaveFunction:
204
+ the results of sampling, as a Qubit Wave Function.
205
+ """
206
+ state = self.initialize_state(self.n_qubits, initial_state).to_operation()
207
+ if state is not None:
208
+ circuit.insert(idx=0, op=state)
209
+ sim = CircuitSimulator(circuit)
210
+ sampled = sim.simulate(samples)
211
+ return self.convert_measurements(backend_result=sampled, target_qubits=read_out_qubits)
212
+
213
+ def initialize_circuit(self, *args, **kwargs) -> QuantumComputation:
214
+ """
215
+ return an empty circuit.
216
+ Parameters
217
+ ----------
218
+ args
219
+ kwargs
220
+
221
+ Returns
222
+ -------
223
+ QuantumComputation
224
+ """
225
+ return QuantumComputation(self.n_qubits, self.n_qubits)
226
+
227
+ def add_parametrized_gate(self, gate, circuit, *args, **kwargs):
228
+ """
229
+ add a parametrized gate.
230
+ Parameters
231
+ ----------
232
+ gate: QGateImpl:
233
+ the gate to add to the circuit.
234
+ circuit:
235
+ the circuit to which the gate is to be added
236
+ args
237
+ kwargs
238
+
239
+ Returns
240
+ -------
241
+ None
242
+ """
243
+ op = self.op_lookup[gate.name]
244
+ parameter = gate.parameter
245
+
246
+ if isinstance(parameter, float):
247
+ par = parameter
248
+ else:
249
+ try:
250
+ par = self.tq_to_ddsim[parameter]
251
+ except Exception:
252
+ var = Variable(
253
+ "{}_{}".format(
254
+ self._name_variable_objective(parameter),
255
+ str(self.counter),
256
+ )
257
+ )
258
+ par = Expression([Term(var, 1)])
259
+ self.tq_to_ddsim[parameter] = var
260
+ self.counter += 1
261
+
262
+ ddsim_gate = SymbolicOperation(
263
+ controls=set(Control(self.qubit(c)) for c in gate.control),
264
+ targets=[self.qubit(t) for t in gate.target],
265
+ op_type=op,
266
+ params=[par],
267
+ )
268
+ circuit.append(ddsim_gate)
269
+
270
+ def add_basic_gate(self, gate, circuit, *args, **kwargs):
271
+ """
272
+ add an unparametrized gate to the circuit.
273
+ Parameters
274
+ ----------
275
+ gate: QGateImpl:
276
+ the gate to be added to the circuit.
277
+ circuit:
278
+ the circuit, to which a gate is to be added.
279
+ args
280
+ kwargs
281
+
282
+ Returns
283
+ -------
284
+ None
285
+ """
286
+ op = self.op_lookup[gate.name]
287
+ ddsim_gate = StandardOperation(
288
+ controls={Control(self.qubit(c)) for c in gate.control},
289
+ targets=[self.qubit(t) for t in gate.target],
290
+ op_type=op,
291
+ )
292
+ circuit.append(ddsim_gate)
293
+
294
+ def add_measurement(self, circuit, target_qubits, *args, **kwargs):
295
+ """
296
+ Add a measurement operation to a circuit.
297
+ Parameters
298
+ ----------
299
+ circuit:
300
+ a circuit, to which the measurement is to be added.
301
+ target_qubits: List[int]
302
+ abstract target qubits
303
+ args
304
+ kwargs
305
+
306
+ Returns
307
+ -------
308
+ circuit with measurements
309
+
310
+ """
311
+ tq = [self.qubit(t) for t in target_qubits]
312
+ meas = NonUnitaryOperation(targets=tq, classics=tq)
313
+ circuit.append(meas)
314
+ return circuit
315
+
316
+ # Overwriting `sample_paulistring` since mqt.ir QuantumComputation object is not pickable:
317
+ # copy.deepcopy fails.
318
+ def sample_paulistring(
319
+ self, samples: int, paulistring, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
320
+ ) -> numbers.Real:
321
+ """
322
+ Sample an individual pauli word (pauli string) and return the average result thereof.
323
+ Parameters
324
+ ----------
325
+ samples: int:
326
+ how many samples to evaluate.
327
+ paulistring:
328
+ the paulistring to be sampled.
329
+ args
330
+ kwargs
331
+
332
+ Returns
333
+ -------
334
+ float:
335
+ the average result of sampling the chosen paulistring
336
+ """
337
+ not_in_u = [q for q in paulistring.qubits if q not in self.abstract_qubits]
338
+ reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u)
339
+ if reduced_ps.coeff == 0.0:
340
+ return 0.0
341
+ if len(reduced_ps._data.keys()) == 0:
342
+ return reduced_ps.coeff
343
+
344
+ # make basis change and translate to backend
345
+ basis_change = QCircuit()
346
+ qubits = []
347
+ for idx, p in reduced_ps.items():
348
+ qubits.append(idx)
349
+ basis_change += change_basis(target=idx, axis=p)
350
+
351
+ # Simple fix to the `copy` problem
352
+ if self.resolver is not None:
353
+ _circuit = self.circuit.instantiate(self.resolver)
354
+ else:
355
+ r = {Variable("_"): 0} # Dummy variable
356
+ _circuit = self.circuit.instantiate(r)
357
+
358
+ # add basis change to the circuit
359
+ # can be circumvented by optimizing the measurements
360
+ # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True)
361
+ circuit = self.create_circuit(circuit=_circuit, abstract_circuit=basis_change)
362
+ # run simulators
363
+ counts = self.sample(
364
+ samples=samples,
365
+ circuit=circuit,
366
+ read_out_qubits=qubits,
367
+ variables=variables,
368
+ initial_state=initial_state,
369
+ *args,
370
+ **kwargs,
371
+ )
372
+ # compute energy
373
+ E = 0.0
374
+ n_samples = 0
375
+ for key, count in counts.items():
376
+ parity = key.array.count(1)
377
+ sign = (-1) ** parity
378
+ E += sign * count
379
+ n_samples += count
380
+ assert n_samples == samples
381
+ E = E / samples * paulistring.coeff
382
+ return E
383
+
384
+
385
+ class BackendExpectationValueDDSim(BackendExpectationValue):
386
+ """
387
+ Class representing Expectation Values compiled for DDSim.
388
+ """
389
+
390
+ BackendCircuitType = BackendCircuitDDSim
@@ -0,0 +1,30 @@
1
+ from mqp.qiskit_provider import MQPProvider, MQPBackend
2
+ from qiskit.circuit import QuantumCircuit
3
+ from mqp.qiskit_provider import MQPProvider, MQPBackend
4
+ from tequila import TequilaException
5
+ from tequila.simulators.simulator_aqt import BackendCircuitAQT, BackendExpectationValueAQT
6
+
7
+
8
+ class BackendCircuitMQP(BackendCircuitAQT):
9
+ def __init__(self, *args, **kwargs):
10
+ super().__init__(*args, **kwargs)
11
+
12
+ # don't transpile the circuit for mqp
13
+ def get_circuit(
14
+ self, circuit: QuantumCircuit, qiskit_backend, initial_state=0, optimization_level=1, *args, **kwargs
15
+ ) -> QuantumCircuit:
16
+ circ = circuit.assign_parameters(self.resolver) # this is necessary -- see qiskit-aer issue 1346
17
+ circ = self.add_state_init(circ, initial_state)
18
+ return circ
19
+
20
+ def do_simulate(self, variables, initial_state=0, *args, **kwargs):
21
+ raise TequilaMQPException("MQP backend does not support do_simulate")
22
+
23
+
24
+ class BackendExpectationValueMQP(BackendExpectationValueAQT):
25
+ BackendCircuitType = BackendCircuitMQP
26
+
27
+
28
+ class TequilaMQPException(TequilaException):
29
+ def __str__(self):
30
+ return "Error in MQP backend:" + self.message