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.
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 +177 -88
  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 +91 -56
  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 +394 -203
  49. tequila/quantumchemistry/encodings.py +121 -13
  50. tequila/quantumchemistry/madness_interface.py +170 -96
  51. tequila/quantumchemistry/orbital_optimizer.py +86 -40
  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 +258 -106
  57. tequila/simulators/simulator_aqt.py +102 -0
  58. tequila/simulators/simulator_base.py +156 -55
  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 +124 -114
  66. tequila/simulators/simulator_qlm.py +52 -26
  67. tequila/simulators/simulator_qulacs.py +85 -59
  68. tequila/simulators/simulator_spex.py +464 -0
  69. tequila/simulators/simulator_symbolic.py +6 -5
  70. tequila/simulators/test_spex_simulator.py +208 -0
  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 +13 -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 +52 -30
  81. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +23 -17
  82. tequila_basic-1.9.10.dist-info/RECORD +93 -0
  83. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
  84. tequila_basic-1.9.8.dist-info/RECORD +0 -86
  85. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info/licenses}/LICENSE +0 -0
  86. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,102 @@
1
+ from calendar import c
2
+ from tequila.utils.keymap import KeyMapRegisterToSubregister
3
+ from tequila import BitString
4
+ from tequila.simulators.simulator_qiskit import (
5
+ BackendCircuitQiskit,
6
+ BackendExpectationValueQiskit,
7
+ TequilaQiskitException,
8
+ )
9
+ from qiskit_aqt_provider import AQTProvider
10
+ from qiskit_aqt_provider.aqt_resource import AQTResource
11
+ from qiskit.circuit import QuantumCircuit
12
+ from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
13
+ from tequila import TequilaException
14
+ import qiskit
15
+ from typing import Union
16
+
17
+
18
+ class TequilaAQTException(TequilaQiskitException):
19
+ def __str__(self):
20
+ return "Error in AQT backend:" + self.message
21
+
22
+
23
+ class BackendCircuitAQT(BackendCircuitQiskit):
24
+ def __init__(self, *args, **kwargs):
25
+ super().__init__(*args, **kwargs)
26
+ if "device" in kwargs.keys() and kwargs["device"] is not None:
27
+ self.device = kwargs["device"]
28
+
29
+ def retrieve_backend(self) -> AQTResource:
30
+ if self.device is None:
31
+ raise TequilaAQTException("No AQT device specified. Please provide a valid AQT device as backend.")
32
+ return self.device
33
+
34
+ # state measurement operation?
35
+ def get_circuit(
36
+ self, circuit: QuantumCircuit, qiskit_backend, initial_state=0, optimization_level=1, *args, **kwargs
37
+ ) -> QuantumCircuit:
38
+ circ = circuit.assign_parameters(self.resolver) # this is necessary -- see qiskit-aer issue 1346
39
+ circ = self.add_state_init(circ, initial_state)
40
+ basis = qiskit_backend.target.operation_names
41
+ circ = qiskit.transpile(circ, backend=qiskit_backend, basis_gates=basis, optimization_level=optimization_level)
42
+ return circ
43
+
44
+ def sample(self, variables, samples, read_out_qubits=None, circuit=None, initial_state=0, *args, **kwargs):
45
+ if initial_state != 0 and not self.supports_sampling_initialization:
46
+ raise TequilaException("Backend does not support initial states for sampling")
47
+
48
+ if isinstance(initial_state, QubitWaveFunction) and not self.supports_generic_initialization:
49
+ raise TequilaException("Backend does not support arbitrary initial states")
50
+
51
+ self.update_variables(variables)
52
+ if read_out_qubits is None:
53
+ read_out_qubits = self.abstract_qubits
54
+
55
+ if len(read_out_qubits) == 0:
56
+ raise Exception("read_out_qubits are empty")
57
+
58
+ if circuit is None:
59
+ circuit = self.add_measurement(circuit=self.circuit, target_qubits=read_out_qubits)
60
+ else:
61
+ if isinstance(circuit, list):
62
+ assert len(circuit) == len(read_out_qubits), "circuit and read_out_qubits have to be of the same length"
63
+ for i, c in enumerate(circuit):
64
+ circuit[i] = self.add_measurement(circuit=c, target_qubits=read_out_qubits[i])
65
+ else:
66
+ circuit = self.add_measurement(circuit=circuit, target_qubits=read_out_qubits)
67
+ return self.do_sample(
68
+ samples=samples,
69
+ circuit=circuit,
70
+ read_out_qubits=read_out_qubits,
71
+ initial_state=initial_state,
72
+ *args,
73
+ **kwargs,
74
+ )
75
+
76
+ def do_sample(
77
+ self, circuit: QuantumCircuit, samples: int, read_out_qubits, initial_state=0, *args, **kwargs
78
+ ) -> QubitWaveFunction:
79
+ optimization_level = 1
80
+ if "optimization_level" in kwargs:
81
+ optimization_level = kwargs["optimization_level"]
82
+ qiskit_backend = self.retrieve_backend()
83
+
84
+ circuit = self.get_circuit(
85
+ circuit=circuit,
86
+ qiskit_backend=qiskit_backend,
87
+ initial_state=initial_state,
88
+ optimization_level=optimization_level,
89
+ *args,
90
+ **kwargs,
91
+ )
92
+ job = qiskit_backend.run(circuit, shots=samples)
93
+ wfn = self.convert_measurements(job, target_qubits=read_out_qubits)
94
+
95
+ return wfn
96
+
97
+ def do_simulate(self, variables, initial_state=0, *args, **kwargs):
98
+ raise TequilaAQTException("AQT backend does not support do_simulate")
99
+
100
+
101
+ class BackendExpectationValueAQT(BackendExpectationValueQiskit):
102
+ BackendCircuitType = BackendCircuitAQT
@@ -1,3 +1,4 @@
1
+ from tequila.circuit._gates_impl import GlobalPhaseGateImpl
1
2
  from tequila.utils import TequilaException, to_float, TequilaWarning
2
3
  from tequila.circuit.circuit import QCircuit
3
4
  from tequila.utils.keymap import KeyMapSubregisterToRegister
@@ -8,8 +9,13 @@ from tequila import BitString
8
9
  from tequila.objective.objective import Variable, format_variable_dictionary
9
10
  from tequila.circuit import compiler
10
11
  from typing import Union
12
+ import numpy as np
11
13
 
12
- import numbers, typing, numpy, copy, warnings
14
+ import numbers
15
+ import typing
16
+ import numpy
17
+ import copy
18
+ import warnings
13
19
 
14
20
  from dataclasses import dataclass
15
21
 
@@ -20,7 +26,7 @@ Todo: Classes are now immutable:
20
26
  """
21
27
 
22
28
 
23
- class BackendCircuit():
29
+ class BackendCircuit:
24
30
  """
25
31
  Base class for circuits compiled to run on specific backends.
26
32
 
@@ -105,7 +111,7 @@ class BackendCircuit():
105
111
  "controlled_phase": True,
106
112
  "toffoli": True,
107
113
  "phase_to_z": True,
108
- "cc_max": True
114
+ "cc_max": True,
109
115
  }
110
116
 
111
117
  # Can be overwritten by backends that allow basis state initialization when sampling
@@ -135,8 +141,17 @@ class BackendCircuit():
135
141
  """
136
142
  return self.qubit_map[abstract_qubit].instance
137
143
 
138
- def __init__(self, abstract_circuit: QCircuit, variables, noise=None, device=None,
139
- qubit_map=None, optimize_circuit=True, *args, **kwargs):
144
+ def __init__(
145
+ self,
146
+ abstract_circuit: QCircuit,
147
+ variables,
148
+ noise=None,
149
+ device=None,
150
+ qubit_map=None,
151
+ optimize_circuit=True,
152
+ *args,
153
+ **kwargs,
154
+ ):
140
155
  """
141
156
 
142
157
  Parameters
@@ -160,8 +175,15 @@ class BackendCircuit():
160
175
  kwargs
161
176
  """
162
177
 
163
- self._input_args = {"abstract_circuit": abstract_circuit, "variables": variables, "noise": noise,
164
- "qubit_map": qubit_map, "optimize_circuits": optimize_circuit, "device": device, **kwargs}
178
+ self._input_args = {
179
+ "abstract_circuit": abstract_circuit,
180
+ "variables": variables,
181
+ "noise": noise,
182
+ "qubit_map": qubit_map,
183
+ "optimize_circuits": optimize_circuit,
184
+ "device": device,
185
+ **kwargs,
186
+ }
165
187
 
166
188
  self.no_translation = False
167
189
  self._variables = tuple(abstract_circuit.extract_variables())
@@ -179,14 +201,24 @@ class BackendCircuit():
179
201
  if qubit_map is None:
180
202
  qubit_map = {q: i for i, q in enumerate(abstract_circuit.qubits)}
181
203
  elif not qubit_map == {q: i for i, q in enumerate(abstract_circuit.qubits)}:
182
- warnings.warn("reveived custom qubit_map = {}\n"
183
- "This is not fully integrated and might result in unexpected behaviour!"
184
- .format(qubit_map), TequilaWarning)
204
+ warnings.warn(
205
+ "reveived custom qubit_map = {}\n"
206
+ "This is not fully integrated and might result in unexpected behaviour!".format(qubit_map),
207
+ TequilaWarning,
208
+ )
185
209
 
186
- if len(qubit_map) > abstract_circuit.max_qubit()+1:
187
- raise TequilaException("Custom qubit_map has too many qubits {} vs {}".format(len(qubit_map), abstract_circuit.max_qubit()+1))
210
+ if len(qubit_map) > abstract_circuit.max_qubit() + 1:
211
+ raise TequilaException(
212
+ "Custom qubit_map has too many qubits {} vs {}".format(
213
+ len(qubit_map), abstract_circuit.max_qubit() + 1
214
+ )
215
+ )
188
216
  if max(qubit_map.keys()) > abstract_circuit.max_qubit():
189
- raise TequilaException("Custom qubit_map tries to assign qubit {} but we only have {}".format(max(qubit_map.keys()), abstract_circuit.max_qubit()))
217
+ raise TequilaException(
218
+ "Custom qubit_map tries to assign qubit {} but we only have {}".format(
219
+ max(qubit_map.keys()), abstract_circuit.max_qubit()
220
+ )
221
+ )
190
222
 
191
223
  # qubit map is initialized to have BackendQubits as values (they carry number and instance attributes)
192
224
  self.qubit_map = self.make_qubit_map(qubit_map)
@@ -195,6 +227,10 @@ class BackendCircuit():
195
227
  compiled = c(abstract_circuit)
196
228
  self.abstract_circuit = compiled
197
229
 
230
+ self.global_phase = sum(g.parameter for g in compiled.gates if isinstance(g, GlobalPhaseGateImpl))
231
+ # Filter out identity and global phase gates because they should not be passed to the backends
232
+ compiled.gates = filter(lambda g: g.name != "I" and not isinstance(g, GlobalPhaseGateImpl), compiled.gates)
233
+
198
234
  self.noise = noise
199
235
  self.check_device(device)
200
236
  self.device = self.retrieve_device(device)
@@ -205,11 +241,7 @@ class BackendCircuit():
205
241
  if optimize_circuit and noise is None:
206
242
  self.circuit = self.optimize_circuit(circuit=self.circuit)
207
243
 
208
- def __call__(self,
209
- variables: typing.Dict[Variable, numbers.Real] = None,
210
- samples: int = None,
211
- *args,
212
- **kwargs):
244
+ def __call__(self, variables: typing.Dict[Variable, numbers.Real] = None, samples: int = None, *args, **kwargs):
213
245
  """
214
246
  Simulate or sample the backend circuit.
215
247
 
@@ -233,7 +265,9 @@ class BackendCircuit():
233
265
  if variables is None or set(self._variables) > set(variables.keys()):
234
266
  raise TequilaException(
235
267
  "BackendCircuit received not all variables. Circuit depends on variables {}, you gave {}".format(
236
- self._variables, variables))
268
+ self._variables, variables
269
+ )
270
+ )
237
271
 
238
272
  self.update_variables(variables)
239
273
  if samples is None:
@@ -269,7 +303,7 @@ class BackendCircuit():
269
303
  result = self.initialize_circuit(*args, **kwargs)
270
304
 
271
305
  for g in abstract_circuit.gates:
272
- if g.is_parametrized():
306
+ if g.is_parameterized():
273
307
  self.add_parametrized_gate(g, result, *args, **kwargs)
274
308
  else:
275
309
  self.add_basic_gate(g, result, *args, **kwargs)
@@ -292,7 +326,7 @@ class BackendCircuit():
292
326
  TequilaException
293
327
  """
294
328
  if device is not None:
295
- raise TequilaException('Devices not enabled for {}'.format(str(type(self))))
329
+ raise TequilaException("Devices not enabled for {}".format(str(type(self))))
296
330
 
297
331
  def retrieve_device(self, device):
298
332
  """
@@ -313,7 +347,7 @@ class BackendCircuit():
313
347
  if device is None:
314
348
  return device
315
349
  else:
316
- raise TequilaException('Devices not enabled for {}'.format(str(type(self))))
350
+ raise TequilaException("Devices not enabled for {}".format(str(type(self))))
317
351
 
318
352
  def add_parametrized_gate(self, gate, circuit, *args, **kwargs):
319
353
  raise TequilaException("Backend Handler needs to be overwritten for supported simulators")
@@ -334,7 +368,9 @@ class BackendCircuit():
334
368
  """
335
369
  self.circuit = self.create_circuit(abstract_circuit=self.abstract_circuit, variables=variables)
336
370
 
337
- def simulate(self, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs) -> QubitWaveFunction:
371
+ def simulate(
372
+ self, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
373
+ ) -> QubitWaveFunction:
338
374
  """
339
375
  simulate the circuit via the backend.
340
376
 
@@ -382,11 +418,17 @@ class BackendCircuit():
382
418
  else:
383
419
  mapped_initial_state = initial_state
384
420
 
385
- result = self.do_simulate(variables=variables, initial_state=mapped_initial_state, *args,
386
- **kwargs)
421
+ result = self.do_simulate(variables=variables, initial_state=mapped_initial_state, *args, **kwargs)
422
+
423
+ # Multiply the state by its global phase (consisting of the sum of the arguments of all global phases)
424
+ # Does currently not support variable parameters
425
+ if isinstance(self.global_phase, float):
426
+ result *= np.exp(1j * self.global_phase)
387
427
 
388
428
  if keymap_required:
389
- result = QubitWaveFunction.from_wavefunction(result, keymap, n_qubits=len(all_qubits), initial_state=initial_state)
429
+ result = QubitWaveFunction.from_wavefunction(
430
+ result, keymap, n_qubits=len(all_qubits), initial_state=initial_state
431
+ )
390
432
 
391
433
  return result
392
434
 
@@ -428,10 +470,18 @@ class BackendCircuit():
428
470
  else:
429
471
  circuit = self.add_measurement(circuit=circuit, target_qubits=read_out_qubits)
430
472
 
431
- return self.do_sample(samples=samples, circuit=circuit, read_out_qubits=read_out_qubits,
432
- initial_state=initial_state, *args, **kwargs)
433
-
434
- def sample_all_z_hamiltonian(self, samples: int, hamiltonian, variables, *args, **kwargs):
473
+ return self.do_sample(
474
+ samples=samples,
475
+ circuit=circuit,
476
+ read_out_qubits=read_out_qubits,
477
+ initial_state=initial_state,
478
+ *args,
479
+ **kwargs,
480
+ )
481
+
482
+ def sample_all_z_hamiltonian(
483
+ self, samples: int, hamiltonian, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
484
+ ):
435
485
  """
436
486
  Sample from a Hamiltonian which only consists of Pauli-Z and unit operators
437
487
  Parameters
@@ -440,6 +490,8 @@ class BackendCircuit():
440
490
  number of samples to take
441
491
  hamiltonian
442
492
  the tequila hamiltonian
493
+ initial_state
494
+ the initial state of the circuit
443
495
  args
444
496
  arguments for do_sample
445
497
  kwargs
@@ -454,11 +506,20 @@ class BackendCircuit():
454
506
  # assert that the Hamiltonian was mapped before
455
507
  if not all(q in self.qubit_map.keys() for q in abstract_qubits_H):
456
508
  raise TequilaException(
457
- "Qubits in {}-qubit Hamiltonian were not traced out for {}-qubit circuit".format(hamiltonian.n_qubits,
458
- self.n_qubits))
509
+ "Qubits in {}-qubit Hamiltonian were not traced out for {}-qubit circuit".format(
510
+ hamiltonian.n_qubits, self.n_qubits
511
+ )
512
+ )
459
513
 
460
514
  # run simulators
461
- counts = self.sample(samples=samples, read_out_qubits=abstract_qubits_H, variables=variables, *args, **kwargs)
515
+ counts = self.sample(
516
+ samples=samples,
517
+ read_out_qubits=abstract_qubits_H,
518
+ variables=variables,
519
+ initial_state=initial_state,
520
+ *args,
521
+ **kwargs,
522
+ )
462
523
  read_out_map = {q: i for i, q in enumerate(abstract_qubits_H)}
463
524
 
464
525
  # compute energy
@@ -481,8 +542,9 @@ class BackendCircuit():
481
542
  assert n_samples == samples
482
543
  return E
483
544
 
484
- def sample_paulistring(self, samples: int, paulistring, variables, *args,
485
- **kwargs) -> numbers.Real:
545
+ def sample_paulistring(
546
+ self, samples: int, paulistring, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
547
+ ) -> numbers.Real:
486
548
  """
487
549
  Sample an individual pauli word (pauli string) and return the average result thereof.
488
550
  Parameters
@@ -520,8 +582,15 @@ class BackendCircuit():
520
582
  # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True)
521
583
  circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit), abstract_circuit=basis_change)
522
584
  # run simulators
523
- counts = self.sample(samples=samples, circuit=circuit, read_out_qubits=qubits, variables=variables, *args,
524
- **kwargs)
585
+ counts = self.sample(
586
+ samples=samples,
587
+ circuit=circuit,
588
+ read_out_qubits=qubits,
589
+ variables=variables,
590
+ initial_state=initial_state,
591
+ *args,
592
+ **kwargs,
593
+ )
525
594
  # compute energy
526
595
  E = 0.0
527
596
  n_samples = 0
@@ -534,7 +603,9 @@ class BackendCircuit():
534
603
  E = E / samples * paulistring.coeff
535
604
  return E
536
605
 
537
- def do_sample(self, samples, circuit, noise, abstract_qubits=None, initial_state=0, *args, **kwargs) -> QubitWaveFunction:
606
+ def do_sample(
607
+ self, samples, circuit, noise, abstract_qubits=None, initial_state=0, *args, **kwargs
608
+ ) -> QubitWaveFunction:
538
609
  """
539
610
  helper function for sampling. MUST be overwritten by inheritors.
540
611
 
@@ -728,6 +799,7 @@ class BackendExpectationValue:
728
799
  wrapper over the update_variables of BackendCircuit.
729
800
 
730
801
  """
802
+
731
803
  BackendCircuitType = BackendCircuit
732
804
 
733
805
  # map to smaller subsystem if there are qubits which are not touched by the circuits,
@@ -792,19 +864,22 @@ class BackendExpectationValue:
792
864
  def __deepcopy__(self, memodict={}):
793
865
  return type(self)(self.abstract_expectationvalue, **self._input_args)
794
866
 
795
- def __call__(self, variables, samples: int = None, *args, **kwargs):
796
-
867
+ def __call__(
868
+ self, variables, samples: int = None, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
869
+ ):
797
870
  variables = format_variable_dictionary(variables=variables)
798
871
  if self._variables is not None and len(self._variables) > 0:
799
872
  if variables is None or (not set(self._variables) <= set(variables.keys())):
800
873
  raise TequilaException(
801
874
  "BackendExpectationValue received not all variables. Circuit depends on variables {}, you gave {}".format(
802
- self._variables, variables))
875
+ self._variables, variables
876
+ )
877
+ )
803
878
 
804
879
  if samples is None:
805
- data = self.simulate(variables=variables, *args, **kwargs)
880
+ data = self.simulate(variables=variables, initial_state=initial_state, *args, **kwargs)
806
881
  else:
807
- data = self.sample(variables=variables, samples=samples, *args, **kwargs)
882
+ data = self.sample(variables=variables, samples=samples, initial_state=initial_state, *args, **kwargs)
808
883
 
809
884
  if self._shape is None and self._contraction is None:
810
885
  # this is the default
@@ -844,15 +919,23 @@ class BackendExpectationValue:
844
919
 
845
920
  def initialize_unitary(self, U, variables, noise, device, *args, **kwargs):
846
921
  """return a compiled unitary"""
847
- return self.BackendCircuitType(abstract_circuit=U, variables=variables, device=device,
848
- use_mapping=self.use_mapping,
849
- noise=noise, *args, **kwargs)
922
+ return self.BackendCircuitType(
923
+ abstract_circuit=U,
924
+ variables=variables,
925
+ device=device,
926
+ use_mapping=self.use_mapping,
927
+ noise=noise,
928
+ *args,
929
+ **kwargs,
930
+ )
850
931
 
851
932
  def update_variables(self, variables):
852
933
  """wrapper over circuit update_variables"""
853
934
  self._U.update_variables(variables=variables)
854
935
 
855
- def sample(self, variables, samples, *args, **kwargs) -> numpy.array:
936
+ def sample(
937
+ self, variables, samples, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs
938
+ ) -> numpy.array:
856
939
  """
857
940
  sample the expectationvalue.
858
941
 
@@ -862,6 +945,8 @@ class BackendExpectationValue:
862
945
  variables to supply to the unitary.
863
946
  samples: int:
864
947
  number of samples to perform.
948
+ initial_state: int or QubitWaveFunction:
949
+ the initial state of the circuit
865
950
  args
866
951
  kwargs
867
952
 
@@ -874,14 +959,21 @@ class BackendExpectationValue:
874
959
  suggested = None
875
960
  if hasattr(samples, "lower") and samples.lower()[:4] == "auto":
876
961
  if self.abstract_expectationvalue.samples is None:
877
- raise TequilaException("samples='auto' requested but no samples where set in individual expectation values")
962
+ raise TequilaException(
963
+ "samples='auto' requested but no samples where set in individual expectation values"
964
+ )
878
965
  total_samples = int(samples[5:])
879
966
  samples = max(1, int(self.abstract_expectationvalue.samples * total_samples))
880
967
  suggested = samples
881
968
  # samples are not necessarily set (either the user has to set it or some functions like optimize_measurements)
882
969
 
883
970
  if suggested is not None and suggested != samples:
884
- warnings.warn("simulating with samples={}, but expectationvalue carries suggested samples={}\nTry calling with samples='auto-total#ofsamples'".format(samples, suggested), TequilaWarning)
971
+ warnings.warn(
972
+ "simulating with samples={}, but expectationvalue carries suggested samples={}\nTry calling with samples='auto-total#ofsamples'".format(
973
+ samples, suggested
974
+ ),
975
+ TequilaWarning,
976
+ )
885
977
 
886
978
  self.update_variables(variables)
887
979
 
@@ -891,16 +983,23 @@ class BackendExpectationValue:
891
983
  if len(H.qubits) == 0:
892
984
  E = sum([ps.coeff for ps in H.paulistrings])
893
985
  elif H.is_all_z():
894
- E = self.U.sample_all_z_hamiltonian(samples=samples, hamiltonian=H, variables=variables, *args,
895
- **kwargs)
986
+ E = self.U.sample_all_z_hamiltonian(
987
+ samples=samples, hamiltonian=H, variables=variables, initial_state=initial_state, *args, **kwargs
988
+ )
896
989
  else:
897
990
  for ps in H.paulistrings:
898
- E += self.U.sample_paulistring(samples=samples, paulistring=ps, variables=variables, *args,
899
- **kwargs)
991
+ E += self.U.sample_paulistring(
992
+ samples=samples,
993
+ paulistring=ps,
994
+ variables=variables,
995
+ initial_state=initial_state,
996
+ *args,
997
+ **kwargs,
998
+ )
900
999
  result.append(to_float(E))
901
1000
  return numpy.asarray(result)
902
1001
 
903
- def simulate(self, variables, *args, **kwargs):
1002
+ def simulate(self, variables, initial_state: Union[int, QubitWaveFunction], *args, **kwargs) -> numpy.array:
904
1003
  """
905
1004
  Simulate the expectationvalue.
906
1005
 
@@ -908,6 +1007,8 @@ class BackendExpectationValue:
908
1007
  ----------
909
1008
  variables:
910
1009
  variables to supply to the unitary.
1010
+ initial_state: int or QubitWaveFunction:
1011
+ the initial state of the circuit
911
1012
  args
912
1013
  kwargs
913
1014
 
@@ -922,7 +1023,7 @@ class BackendExpectationValue:
922
1023
  final_E = 0.0
923
1024
  # TODO inefficient,
924
1025
  # Always better to overwrite this function
925
- wfn = self.U.simulate(variables=variables, *args, **kwargs)
1026
+ wfn = self.U.simulate(variables=variables, initial_state=initial_state, *args, **kwargs)
926
1027
  final_E += wfn.compute_expectationvalue(operator=H)
927
1028
  result.append(to_float(final_E))
928
1029
  return numpy.asarray(result)