tequila-basic 1.9.7__py3-none-any.whl → 1.9.9__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/apps/unary_state_prep.py +1 -2
- tequila/circuit/circuit.py +20 -15
- tequila/hamiltonian/paulis.py +4 -3
- tequila/objective/objective.py +5 -2
- tequila/quantumchemistry/chemistry_tools.py +8 -1
- tequila/quantumchemistry/encodings.py +2 -2
- tequila/quantumchemistry/orbital_optimizer.py +10 -2
- tequila/simulators/simulator_api.py +35 -9
- tequila/simulators/simulator_base.py +58 -28
- tequila/simulators/simulator_cirq.py +6 -6
- tequila/simulators/simulator_pyquil.py +3 -3
- tequila/simulators/simulator_qibo.py +14 -16
- tequila/simulators/simulator_qiskit.py +88 -53
- tequila/simulators/simulator_qiskit_gpu.py +9 -0
- tequila/simulators/simulator_qlm.py +3 -3
- tequila/simulators/simulator_qulacs.py +37 -28
- tequila/simulators/simulator_qulacs_gpu.py +6 -4
- tequila/simulators/simulator_spex.py +429 -0
- tequila/simulators/simulator_symbolic.py +15 -23
- tequila/simulators/test_spex_simulator.py +211 -0
- tequila/utils/bitstrings.py +14 -3
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +340 -237
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.9.dist-info}/METADATA +13 -9
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.9.dist-info}/RECORD +28 -25
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.9.dist-info}/WHEEL +1 -1
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.9.dist-info/licenses}/LICENSE +0 -0
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.9.dist-info}/top_level.txt +0 -0
tequila/apps/unary_state_prep.py
CHANGED
@@ -89,7 +89,6 @@ class UnaryStatePrep:
|
|
89
89
|
simulator.convert_to_numpy = False
|
90
90
|
variables = None # {k:k.name.evalf() for k in self._abstract_circuit.extract_variables()}
|
91
91
|
wfn = simulator.simulate(initial_state=BitString.from_int(0, nbits=self.n_qubits), variables=variables)
|
92
|
-
wfn.n_qubits = self._n_qubits
|
93
92
|
equations = []
|
94
93
|
for k in target_space:
|
95
94
|
equations.append(wfn[k] - abstract_coefficients[k])
|
@@ -174,7 +173,7 @@ class UnaryStatePrep:
|
|
174
173
|
:return:
|
175
174
|
"""
|
176
175
|
try:
|
177
|
-
assert (
|
176
|
+
assert wfn.length() == len(self._target_space)
|
178
177
|
for key in wfn.keys():
|
179
178
|
try:
|
180
179
|
assert (key in self._target_space)
|
tequila/circuit/circuit.py
CHANGED
@@ -9,6 +9,7 @@ import warnings
|
|
9
9
|
|
10
10
|
from .qpic import export_to
|
11
11
|
|
12
|
+
|
12
13
|
class QCircuit():
|
13
14
|
"""
|
14
15
|
Fundamental class representing an abstract circuit.
|
@@ -254,8 +255,8 @@ class QCircuit():
|
|
254
255
|
the gates to add at the corresponding positions
|
255
256
|
replace: list of bool: (Default value: None)
|
256
257
|
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
|
258
|
+
decide if gates shall be replaced or if the new parts shall be inserted without replacement
|
259
|
+
if replace[i] = true: gate at position [i] will be replaced by gates[i]
|
259
260
|
if replace[i] = false: gates[i] circuit will be inserted at position [i] (beaming before gate previously at position [i])
|
260
261
|
Returns
|
261
262
|
-------
|
@@ -271,8 +272,9 @@ class QCircuit():
|
|
271
272
|
dataset = zip(positions, circuits, replace)
|
272
273
|
dataset = sorted(dataset, key=lambda x: x[0])
|
273
274
|
|
274
|
-
|
275
|
-
|
275
|
+
new_gatelist = []
|
276
|
+
last_idx = -1
|
277
|
+
|
276
278
|
for idx, circuit, do_replace in dataset:
|
277
279
|
|
278
280
|
# failsafe
|
@@ -283,13 +285,14 @@ class QCircuit():
|
|
283
285
|
else:
|
284
286
|
gatelist = [circuit]
|
285
287
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
288
|
+
new_gatelist += self.gates[last_idx + 1:idx]
|
289
|
+
new_gatelist += gatelist
|
290
|
+
if not do_replace:
|
291
|
+
new_gatelist.append(self.gates[idx])
|
292
|
+
|
293
|
+
last_idx = idx
|
294
|
+
|
295
|
+
new_gatelist += self.gates[last_idx + 1:]
|
293
296
|
|
294
297
|
result = QCircuit(gates=new_gatelist)
|
295
298
|
result.n_qubits = max(result.n_qubits, self.n_qubits)
|
@@ -386,7 +389,7 @@ class QCircuit():
|
|
386
389
|
for k, v in other._parameter_map.items():
|
387
390
|
self._parameter_map[k] += [(x[0] + offset, x[1]) for x in v]
|
388
391
|
|
389
|
-
self._gates +=
|
392
|
+
self._gates += other.gates
|
390
393
|
self._min_n_qubits = max(self._min_n_qubits, other._min_n_qubits)
|
391
394
|
|
392
395
|
return self
|
@@ -593,7 +596,7 @@ class QCircuit():
|
|
593
596
|
|
594
597
|
This is an in-place method, so it mutates self and doesn't return any value.
|
595
598
|
|
596
|
-
Raise TequilaWarning if there any qubits in common between self and control.
|
599
|
+
Raise TequilaWarning if there are any qubits in common between self and control.
|
597
600
|
"""
|
598
601
|
gates = self.gates
|
599
602
|
control = list_assignment(control)
|
@@ -610,8 +613,10 @@ class QCircuit():
|
|
610
613
|
if len(control_lst) < len(gate.control) + len(control):
|
611
614
|
# warnings.warn("Some of the controls {} were already included in the control "
|
612
615
|
# "of a gate {}.".format(control, gate), TequilaWarning)
|
613
|
-
raise TequilaWarning(f
|
614
|
-
f
|
616
|
+
raise TequilaWarning(f"Some of the controls {control} were already included "
|
617
|
+
f"in the control of a gate {gate}. "
|
618
|
+
f"This might be because the same instance of a gate is used in multiple places, "
|
619
|
+
f"e.g. because the same circuit was appended twice.")
|
615
620
|
else:
|
616
621
|
control_lst, not_control = list(control), list()
|
617
622
|
|
tequila/hamiltonian/paulis.py
CHANGED
@@ -256,7 +256,7 @@ def Projector(wfn, threshold=0.0, n_qubits=None) -> QubitHamiltonian:
|
|
256
256
|
|
257
257
|
"""
|
258
258
|
|
259
|
-
wfn = QubitWaveFunction(
|
259
|
+
wfn = QubitWaveFunction.convert_from(n_qubits, wfn)
|
260
260
|
|
261
261
|
H = QubitHamiltonian.zero()
|
262
262
|
for k1, v1 in wfn.items():
|
@@ -304,8 +304,9 @@ def KetBra(ket: QubitWaveFunction, bra: QubitWaveFunction, hermitian: bool = Fal
|
|
304
304
|
|
305
305
|
"""
|
306
306
|
H = QubitHamiltonian.zero()
|
307
|
-
|
308
|
-
|
307
|
+
|
308
|
+
ket = QubitWaveFunction.convert_from(n_qubits, ket)
|
309
|
+
bra = QubitWaveFunction.convert_from(n_qubits, bra)
|
309
310
|
|
310
311
|
for k1, v1 in bra.items():
|
311
312
|
for k2, v2 in ket.items():
|
tequila/objective/objective.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import typing, copy, numbers
|
2
|
+
from typing import Union
|
2
3
|
from tequila.grouping.compile_groups import compile_commuting_parts
|
3
4
|
from tequila import TequilaException
|
4
5
|
from tequila.utils import JoinedTransformation
|
@@ -545,7 +546,7 @@ class Objective:
|
|
545
546
|
"variables = {}\n" \
|
546
547
|
"types = {}".format(unique, measurements, variables, types)
|
547
548
|
|
548
|
-
def __call__(self, variables=None, *args, **kwargs):
|
549
|
+
def __call__(self, variables=None, initial_state = 0, *args, **kwargs):
|
549
550
|
"""
|
550
551
|
Return the output of the calculation the objective represents.
|
551
552
|
|
@@ -553,6 +554,8 @@ class Objective:
|
|
553
554
|
----------
|
554
555
|
variables: dict:
|
555
556
|
dictionary instantiating all variables that may appear within the objective.
|
557
|
+
initial_state: int or QubitWaveFunction:
|
558
|
+
the initial state of the circuit
|
556
559
|
args
|
557
560
|
kwargs
|
558
561
|
|
@@ -579,7 +582,7 @@ class Objective:
|
|
579
582
|
ev_array = []
|
580
583
|
for E in self.args:
|
581
584
|
if E not in evaluated: #
|
582
|
-
expval_result = E(variables=variables, *args, **kwargs)
|
585
|
+
expval_result = E(variables=variables, initial_state=initial_state, *args, **kwargs)
|
583
586
|
evaluated[E] = expval_result
|
584
587
|
else:
|
585
588
|
expval_result = evaluated[E]
|
@@ -442,7 +442,14 @@ class ParametersQC:
|
|
442
442
|
for i in range(natoms):
|
443
443
|
coord += content[2 + i]
|
444
444
|
return coord, comment
|
445
|
-
|
445
|
+
def get_xyz(self)->str:
|
446
|
+
geom = self.parameters.get_geometry()
|
447
|
+
f = ''
|
448
|
+
f += f'{len(geom)}\n'
|
449
|
+
f += f'{self.parameters.name}\n'
|
450
|
+
for at in geom:
|
451
|
+
f += f'{at[0]} {at[1][0]} {at[1][1]} {at[1][2]}\n'
|
452
|
+
return f
|
446
453
|
|
447
454
|
@dataclass
|
448
455
|
class ClosedShellAmplitudes:
|
@@ -128,9 +128,9 @@ class EncodingBase(metaclass=abc.ABCMeta):
|
|
128
128
|
fop = openfermion.FermionOperator(string, 1.0)
|
129
129
|
op = self(fop)
|
130
130
|
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
|
131
|
-
wfn = QubitWaveFunction.
|
131
|
+
wfn = QubitWaveFunction.from_basis_state(n_qubits, 0)
|
132
132
|
wfn = wfn.apply_qubitoperator(operator=op)
|
133
|
-
assert
|
133
|
+
assert wfn.length() == 1
|
134
134
|
key = list(wfn.keys())[0].array
|
135
135
|
return key
|
136
136
|
|
@@ -208,11 +208,17 @@ class PySCFVQEWrapper:
|
|
208
208
|
H = molecule.make_hardcore_boson_hamiltonian()
|
209
209
|
else:
|
210
210
|
H = molecule.make_hamiltonian()
|
211
|
+
|
212
|
+
rdm1 = None
|
213
|
+
rdm2 = None
|
211
214
|
if self.vqe_solver is not None:
|
212
215
|
vqe_solver_arguments = {}
|
213
216
|
if self.vqe_solver_arguments is not None:
|
214
217
|
vqe_solver_arguments = self.vqe_solver_arguments
|
215
218
|
result = self.vqe_solver(H=H, circuit=self.circuit, molecule=molecule, **vqe_solver_arguments)
|
219
|
+
if hasattr(self.vqe_solver, "compute_rdms"):
|
220
|
+
rdm1,rdm2 = self.vqe_solver.compute_rdms(U=self.circuit, variables=result.variables, molecule=molecule, use_hcb=restrict_to_hcb)
|
221
|
+
rdm2 = self.reorder(rdm2, 'dirac', 'mulliken')
|
216
222
|
elif self.circuit is None:
|
217
223
|
raise Exception("Orbital Optimizer: Either provide a callable vqe_solver or a circuit")
|
218
224
|
else:
|
@@ -233,8 +239,9 @@ class PySCFVQEWrapper:
|
|
233
239
|
# static ansatz
|
234
240
|
U = self.circuit
|
235
241
|
|
236
|
-
rdm1
|
237
|
-
|
242
|
+
if rdm1 is None or rdm2 is None:
|
243
|
+
rdm1, rdm2 = molecule.compute_rdms(U=U, variables=result.variables, spin_free=True, get_rdm1=True, get_rdm2=True, use_hcb=restrict_to_hcb)
|
244
|
+
rdm2 = self.reorder(rdm2, 'dirac', 'mulliken')
|
238
245
|
if not self.silent:
|
239
246
|
print("{:20} : {}".format("energy", result.energy))
|
240
247
|
if len(self.history) > 0:
|
@@ -259,3 +266,4 @@ class PySCFVQEWrapper:
|
|
259
266
|
else:
|
260
267
|
result += "{:30} : {}\n".format(k, v)
|
261
268
|
return result
|
269
|
+
|
@@ -9,9 +9,11 @@ from tequila.objective import Objective, Variable, assign_variable, format_varia
|
|
9
9
|
from tequila.utils.exceptions import TequilaException, TequilaWarning
|
10
10
|
from tequila.simulators.simulator_base import BackendCircuit, BackendExpectationValue
|
11
11
|
from tequila.circuit.noise import NoiseModel
|
12
|
+
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
|
12
13
|
|
13
|
-
SUPPORTED_BACKENDS = ["
|
14
|
-
|
14
|
+
SUPPORTED_BACKENDS = ["qulacs", "qulacs_gpu", "qibo", "qiskit", "qiskit_gpu", "cirq", "pyquil", "symbolic", "qlm", "spex"]
|
15
|
+
# TODO: Reenable noise for Qiskit
|
16
|
+
SUPPORTED_NOISE_BACKENDS = ["cirq", "pyquil"] # qulacs removed in v.1.9
|
15
17
|
BackendTypes = namedtuple('BackendTypes', 'CircType ExpValueType')
|
16
18
|
INSTALLED_SIMULATORS = {}
|
17
19
|
INSTALLED_SAMPLERS = {}
|
@@ -22,7 +24,6 @@ if typing.TYPE_CHECKING:
|
|
22
24
|
from tequila.objective import Objective, Variable
|
23
25
|
from tequila.circuit.gates import QCircuit
|
24
26
|
import numbers.Real as RealNumber
|
25
|
-
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
|
26
27
|
|
27
28
|
"""
|
28
29
|
Check which simulators are installed
|
@@ -30,6 +31,15 @@ We are distinguishing two classes of simulators: Samplers and full wavefunction
|
|
30
31
|
"""
|
31
32
|
|
32
33
|
|
34
|
+
HAS_SPEX = True
|
35
|
+
try:
|
36
|
+
from tequila.simulators.simulator_spex import BackendCircuitSpex, BackendExpectationValueSpex
|
37
|
+
|
38
|
+
INSTALLED_SIMULATORS["spex"] = BackendTypes(BackendCircuitSpex, BackendExpectationValueSpex)
|
39
|
+
except ImportError:
|
40
|
+
HAS_SPEX = False
|
41
|
+
|
42
|
+
|
33
43
|
HAS_QISKIT = True
|
34
44
|
try:
|
35
45
|
from tequila.simulators.simulator_qiskit import BackendCircuitQiskit, BackendExpectationValueQiskit
|
@@ -43,6 +53,19 @@ except ImportError:
|
|
43
53
|
HAS_QISKIT = False
|
44
54
|
HAS_QISKIT_NOISE = False
|
45
55
|
|
56
|
+
try:
|
57
|
+
pkg_resources.require("qiskit-aer-gpu")
|
58
|
+
from tequila.simulators.simulator_qiskit_gpu import BackendCircuitQiskitGpu, BackendExpectationValueQiskitGpu
|
59
|
+
HAS_QISKIT_GPU = True
|
60
|
+
INSTALLED_SIMULATORS["qiskit_gpu"] = BackendTypes(BackendCircuitQiskitGpu, BackendExpectationValueQiskitGpu)
|
61
|
+
INSTALLED_SAMPLERS["qiskit_gpu"] = BackendTypes(BackendCircuitQiskitGpu, BackendExpectationValueQiskitGpu)
|
62
|
+
from tequila.simulators.simulator_qiskit import HAS_NOISE as HAS_QISKIT_GPU_NOISE
|
63
|
+
if HAS_QISKIT_GPU_NOISE:
|
64
|
+
INSTALLED_NOISE_SAMPLERS["qiskit_gpu"] = BackendTypes(BackendCircuitQiskitGpu, BackendExpectationValueQiskitGpu)
|
65
|
+
except (ImportError, DistributionNotFound):
|
66
|
+
HAS_QISKIT_GPU = False
|
67
|
+
HAS_QISKIT_GPU_NOISE = False
|
68
|
+
|
46
69
|
HAS_QIBO = True
|
47
70
|
try:
|
48
71
|
from tequila.simulators.simulator_qibo import BackendCircuitQibo, BackendExpectationValueQibo
|
@@ -82,8 +105,8 @@ except (ImportError, DistributionNotFound):
|
|
82
105
|
HAS_QULACS = False
|
83
106
|
|
84
107
|
try:
|
85
|
-
pkg_resources.require("qulacs-gpu")
|
86
|
-
import
|
108
|
+
# pkg_resources.require("qulacs-gpu")
|
109
|
+
from qulacs import QuantumStateGpu
|
87
110
|
from tequila.simulators.simulator_qulacs_gpu import BackendCircuitQulacsGpu, BackendExpectationValueQulacsGpu
|
88
111
|
|
89
112
|
HAS_QULACS_GPU = True
|
@@ -350,14 +373,15 @@ def compile_circuit(abstract_circuit: 'QCircuit',
|
|
350
373
|
return CircType(abstract_circuit=abstract_circuit, variables=variables, noise=noise, device=device, *args, **kwargs)
|
351
374
|
|
352
375
|
|
353
|
-
def simulate(objective: typing.Union['Objective', 'QCircuit','QTensor'],
|
376
|
+
def simulate(objective: typing.Union['Objective', 'QCircuit', 'QTensor'],
|
354
377
|
variables: Dict[Union[Variable, Hashable], RealNumber] = None,
|
355
378
|
samples: int = None,
|
356
379
|
backend: str = None,
|
357
380
|
noise: NoiseModel = None,
|
358
381
|
device: str = None,
|
382
|
+
initial_state: Union[int, QubitWaveFunction] = 0,
|
359
383
|
*args,
|
360
|
-
**kwargs) -> Union[RealNumber,
|
384
|
+
**kwargs) -> Union[RealNumber, QubitWaveFunction]:
|
361
385
|
"""Simulate a tequila objective or circuit
|
362
386
|
|
363
387
|
Parameters
|
@@ -375,6 +399,8 @@ def simulate(objective: typing.Union['Objective', 'QCircuit','QTensor'],
|
|
375
399
|
specify a noise model to apply to simulation/sampling
|
376
400
|
device:
|
377
401
|
a device upon which (or in emulation of which) to sample
|
402
|
+
initial_state: int or QubitWaveFunction:
|
403
|
+
the initial state of the circuit
|
378
404
|
*args :
|
379
405
|
|
380
406
|
**kwargs :
|
@@ -394,9 +420,9 @@ def simulate(objective: typing.Union['Objective', 'QCircuit','QTensor'],
|
|
394
420
|
objective.extract_variables()))
|
395
421
|
|
396
422
|
compiled_objective = compile(objective=objective, samples=samples, variables=variables, backend=backend,
|
397
|
-
noise=noise,device=device, *args, **kwargs)
|
423
|
+
noise=noise, device=device, *args, **kwargs)
|
398
424
|
|
399
|
-
return compiled_objective(variables=variables, samples=samples, *args, **kwargs)
|
425
|
+
return compiled_objective(variables=variables, samples=samples, initial_state=initial_state, *args, **kwargs)
|
400
426
|
|
401
427
|
|
402
428
|
def draw(objective, variables=None, backend: str = None, name=None, *args, **kwargs):
|
@@ -7,6 +7,7 @@ from tequila.circuit.compiler import change_basis
|
|
7
7
|
from tequila import BitString
|
8
8
|
from tequila.objective.objective import Variable, format_variable_dictionary
|
9
9
|
from tequila.circuit import compiler
|
10
|
+
from typing import Union
|
10
11
|
|
11
12
|
import numbers, typing, numpy, copy, warnings
|
12
13
|
|
@@ -107,6 +108,11 @@ class BackendCircuit():
|
|
107
108
|
"cc_max": True
|
108
109
|
}
|
109
110
|
|
111
|
+
# Can be overwritten by backends that allow basis state initialization when sampling
|
112
|
+
supports_sampling_initialization: bool = False
|
113
|
+
# Can be overwritten by backends that allow initializing arbitrary states
|
114
|
+
supports_generic_initialization: bool = False
|
115
|
+
|
110
116
|
@property
|
111
117
|
def n_qubits(self) -> numbers.Integral:
|
112
118
|
return len(self.qubit_map)
|
@@ -328,7 +334,7 @@ class BackendCircuit():
|
|
328
334
|
"""
|
329
335
|
self.circuit = self.create_circuit(abstract_circuit=self.abstract_circuit, variables=variables)
|
330
336
|
|
331
|
-
def simulate(self, variables, initial_state=0, *args, **kwargs) -> QubitWaveFunction:
|
337
|
+
def simulate(self, variables, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs) -> QubitWaveFunction:
|
332
338
|
"""
|
333
339
|
simulate the circuit via the backend.
|
334
340
|
|
@@ -348,13 +354,12 @@ class BackendCircuit():
|
|
348
354
|
the wavefunction of the system produced by the action of the circuit on the initial state.
|
349
355
|
|
350
356
|
"""
|
357
|
+
if isinstance(initial_state, QubitWaveFunction) and not self.supports_generic_initialization:
|
358
|
+
raise TequilaException("Backend does not support arbitrary initial states")
|
359
|
+
|
351
360
|
self.update_variables(variables)
|
352
361
|
if isinstance(initial_state, BitString):
|
353
362
|
initial_state = initial_state.integer
|
354
|
-
if isinstance(initial_state, QubitWaveFunction):
|
355
|
-
if len(initial_state.keys()) != 1:
|
356
|
-
raise TequilaException("only product states as initial states accepted")
|
357
|
-
initial_state = list(initial_state.keys())[0].integer
|
358
363
|
|
359
364
|
all_qubits = list(range(self.abstract_circuit.n_qubits))
|
360
365
|
active_qubits = self.qubit_map.keys()
|
@@ -362,20 +367,30 @@ class BackendCircuit():
|
|
362
367
|
# Keymap is only necessary if not all qubits are active
|
363
368
|
keymap_required = sorted(active_qubits) != all_qubits
|
364
369
|
|
370
|
+
# Combining keymap and general initial states is awkward, because it's not clear what should happen with
|
371
|
+
# different states on non-active qubits. For now, this is simply not allowed.
|
372
|
+
# A better solution might be to check if all components of the initial state differ only on the active qubits.
|
373
|
+
if keymap_required and isinstance(initial_state, QubitWaveFunction):
|
374
|
+
raise TequilaException("Can only set non-basis initial state if all qubits are used")
|
375
|
+
|
365
376
|
if keymap_required:
|
366
377
|
# maps from reduced register to full register
|
367
378
|
keymap = KeyMapSubregisterToRegister(subregister=active_qubits, register=all_qubits)
|
368
379
|
|
369
|
-
|
380
|
+
if not isinstance(initial_state, QubitWaveFunction):
|
381
|
+
mapped_initial_state = keymap.inverted(initial_state).integer if keymap_required else int(initial_state)
|
382
|
+
else:
|
383
|
+
mapped_initial_state = initial_state
|
384
|
+
|
370
385
|
result = self.do_simulate(variables=variables, initial_state=mapped_initial_state, *args,
|
371
386
|
**kwargs)
|
372
387
|
|
373
388
|
if keymap_required:
|
374
|
-
result.
|
389
|
+
result = QubitWaveFunction.from_wavefunction(result, keymap, n_qubits=len(all_qubits), initial_state=initial_state)
|
375
390
|
|
376
391
|
return result
|
377
392
|
|
378
|
-
def sample(self, variables, samples, read_out_qubits=None, circuit=None, *args, **kwargs):
|
393
|
+
def sample(self, variables, samples, read_out_qubits=None, circuit=None, initial_state=0, *args, **kwargs):
|
379
394
|
"""
|
380
395
|
Sample the circuit. If circuit natively equips paulistrings, sample therefrom.
|
381
396
|
Parameters
|
@@ -395,6 +410,12 @@ class BackendCircuit():
|
|
395
410
|
The result of sampling, a recreated QubitWaveFunction in the sampled basis.
|
396
411
|
|
397
412
|
"""
|
413
|
+
if initial_state != 0 and not self.supports_sampling_initialization:
|
414
|
+
raise TequilaException("Backend does not support initial states for sampling")
|
415
|
+
|
416
|
+
if isinstance(initial_state, QubitWaveFunction) and not self.supports_generic_initialization:
|
417
|
+
raise TequilaException("Backend does not support arbitrary initial states")
|
418
|
+
|
398
419
|
self.update_variables(variables)
|
399
420
|
if read_out_qubits is None:
|
400
421
|
read_out_qubits = self.abstract_qubits
|
@@ -406,9 +427,12 @@ class BackendCircuit():
|
|
406
427
|
circuit = self.add_measurement(circuit=self.circuit, target_qubits=read_out_qubits)
|
407
428
|
else:
|
408
429
|
circuit = self.add_measurement(circuit=circuit, target_qubits=read_out_qubits)
|
409
|
-
return self.do_sample(samples=samples, circuit=circuit, read_out_qubits=read_out_qubits, *args, **kwargs)
|
410
430
|
|
411
|
-
|
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,
|
435
|
+
initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs):
|
412
436
|
"""
|
413
437
|
Sample from a Hamiltonian which only consists of Pauli-Z and unit operators
|
414
438
|
Parameters
|
@@ -417,6 +441,8 @@ class BackendCircuit():
|
|
417
441
|
number of samples to take
|
418
442
|
hamiltonian
|
419
443
|
the tequila hamiltonian
|
444
|
+
initial_state
|
445
|
+
the initial state of the circuit
|
420
446
|
args
|
421
447
|
arguments for do_sample
|
422
448
|
kwargs
|
@@ -435,7 +461,7 @@ class BackendCircuit():
|
|
435
461
|
self.n_qubits))
|
436
462
|
|
437
463
|
# run simulators
|
438
|
-
counts = self.sample(samples=samples, read_out_qubits=abstract_qubits_H, variables=variables, *args, **kwargs)
|
464
|
+
counts = self.sample(samples=samples, read_out_qubits=abstract_qubits_H, variables=variables, initial_state=initial_state, *args, **kwargs)
|
439
465
|
read_out_map = {q: i for i, q in enumerate(abstract_qubits_H)}
|
440
466
|
|
441
467
|
# compute energy
|
@@ -458,8 +484,8 @@ class BackendCircuit():
|
|
458
484
|
assert n_samples == samples
|
459
485
|
return E
|
460
486
|
|
461
|
-
def sample_paulistring(self, samples: int, paulistring, variables,
|
462
|
-
**kwargs) -> numbers.Real:
|
487
|
+
def sample_paulistring(self, samples: int, paulistring, variables, initial_state: Union[int, QubitWaveFunction] = 0,
|
488
|
+
*args, **kwargs) -> numbers.Real:
|
463
489
|
"""
|
464
490
|
Sample an individual pauli word (pauli string) and return the average result thereof.
|
465
491
|
Parameters
|
@@ -497,8 +523,8 @@ class BackendCircuit():
|
|
497
523
|
# on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True)
|
498
524
|
circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit), abstract_circuit=basis_change)
|
499
525
|
# run simulators
|
500
|
-
counts = self.sample(samples=samples, circuit=circuit, read_out_qubits=qubits, variables=variables,
|
501
|
-
**kwargs)
|
526
|
+
counts = self.sample(samples=samples, circuit=circuit, read_out_qubits=qubits, variables=variables,
|
527
|
+
initial_state=initial_state, *args, **kwargs)
|
502
528
|
# compute energy
|
503
529
|
E = 0.0
|
504
530
|
n_samples = 0
|
@@ -511,7 +537,7 @@ class BackendCircuit():
|
|
511
537
|
E = E / samples * paulistring.coeff
|
512
538
|
return E
|
513
539
|
|
514
|
-
def do_sample(self, samples, circuit, noise, abstract_qubits=None, *args, **kwargs) -> QubitWaveFunction:
|
540
|
+
def do_sample(self, samples, circuit, noise, abstract_qubits=None, initial_state=0, *args, **kwargs) -> QubitWaveFunction:
|
515
541
|
"""
|
516
542
|
helper function for sampling. MUST be overwritten by inheritors.
|
517
543
|
|
@@ -769,7 +795,7 @@ class BackendExpectationValue:
|
|
769
795
|
def __deepcopy__(self, memodict={}):
|
770
796
|
return type(self)(self.abstract_expectationvalue, **self._input_args)
|
771
797
|
|
772
|
-
def __call__(self, variables, samples: int = None, *args, **kwargs):
|
798
|
+
def __call__(self, variables, samples: int = None, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs):
|
773
799
|
|
774
800
|
variables = format_variable_dictionary(variables=variables)
|
775
801
|
if self._variables is not None and len(self._variables) > 0:
|
@@ -777,11 +803,11 @@ class BackendExpectationValue:
|
|
777
803
|
raise TequilaException(
|
778
804
|
"BackendExpectationValue received not all variables. Circuit depends on variables {}, you gave {}".format(
|
779
805
|
self._variables, variables))
|
780
|
-
|
806
|
+
|
781
807
|
if samples is None:
|
782
|
-
data = self.simulate(variables=variables, *args, **kwargs)
|
808
|
+
data = self.simulate(variables=variables, initial_state=initial_state, *args, **kwargs)
|
783
809
|
else:
|
784
|
-
data = self.sample(variables=variables, samples=samples, *args, **kwargs)
|
810
|
+
data = self.sample(variables=variables, samples=samples, initial_state=initial_state, *args, **kwargs)
|
785
811
|
|
786
812
|
if self._shape is None and self._contraction is None:
|
787
813
|
# this is the default
|
@@ -829,7 +855,7 @@ class BackendExpectationValue:
|
|
829
855
|
"""wrapper over circuit update_variables"""
|
830
856
|
self._U.update_variables(variables=variables)
|
831
857
|
|
832
|
-
def sample(self, variables, samples, *args, **kwargs) -> numpy.array:
|
858
|
+
def sample(self, variables, samples, initial_state: Union[int, QubitWaveFunction] = 0, *args, **kwargs) -> numpy.array:
|
833
859
|
"""
|
834
860
|
sample the expectationvalue.
|
835
861
|
|
@@ -839,6 +865,8 @@ class BackendExpectationValue:
|
|
839
865
|
variables to supply to the unitary.
|
840
866
|
samples: int:
|
841
867
|
number of samples to perform.
|
868
|
+
initial_state: int or QubitWaveFunction:
|
869
|
+
the initial state of the circuit
|
842
870
|
args
|
843
871
|
kwargs
|
844
872
|
|
@@ -856,7 +884,7 @@ class BackendExpectationValue:
|
|
856
884
|
samples = max(1, int(self.abstract_expectationvalue.samples * total_samples))
|
857
885
|
suggested = samples
|
858
886
|
# samples are not necessarily set (either the user has to set it or some functions like optimize_measurements)
|
859
|
-
|
887
|
+
|
860
888
|
if suggested is not None and suggested != samples:
|
861
889
|
warnings.warn("simulating with samples={}, but expectationvalue carries suggested samples={}\nTry calling with samples='auto-total#ofsamples'".format(samples, suggested), TequilaWarning)
|
862
890
|
|
@@ -868,16 +896,16 @@ class BackendExpectationValue:
|
|
868
896
|
if len(H.qubits) == 0:
|
869
897
|
E = sum([ps.coeff for ps in H.paulistrings])
|
870
898
|
elif H.is_all_z():
|
871
|
-
E = self.U.sample_all_z_hamiltonian(samples=samples, hamiltonian=H, variables=variables,
|
872
|
-
|
899
|
+
E = self.U.sample_all_z_hamiltonian(samples=samples, hamiltonian=H, variables=variables, initial_state=initial_state,
|
900
|
+
*args, **kwargs)
|
873
901
|
else:
|
874
902
|
for ps in H.paulistrings:
|
875
|
-
E += self.U.sample_paulistring(samples=samples, paulistring=ps, variables=variables,
|
876
|
-
**kwargs)
|
903
|
+
E += self.U.sample_paulistring(samples=samples, paulistring=ps, variables=variables, initial_state=initial_state,
|
904
|
+
*args, **kwargs)
|
877
905
|
result.append(to_float(E))
|
878
906
|
return numpy.asarray(result)
|
879
907
|
|
880
|
-
def simulate(self, variables, *args, **kwargs):
|
908
|
+
def simulate(self, variables, initial_state: Union[int, QubitWaveFunction], *args, **kwargs):
|
881
909
|
"""
|
882
910
|
Simulate the expectationvalue.
|
883
911
|
|
@@ -885,6 +913,8 @@ class BackendExpectationValue:
|
|
885
913
|
----------
|
886
914
|
variables:
|
887
915
|
variables to supply to the unitary.
|
916
|
+
initial_state: int or QubitWaveFunction:
|
917
|
+
the initial state of the circuit
|
888
918
|
args
|
889
919
|
kwargs
|
890
920
|
|
@@ -899,7 +929,7 @@ class BackendExpectationValue:
|
|
899
929
|
final_E = 0.0
|
900
930
|
# TODO inefficient,
|
901
931
|
# Always better to overwrite this function
|
902
|
-
wfn = self.U.simulate(variables=variables, *args, **kwargs)
|
932
|
+
wfn = self.U.simulate(variables=variables, initial_state=initial_state, *args, **kwargs)
|
903
933
|
final_E += wfn.compute_expectationvalue(operator=H)
|
904
934
|
result.append(to_float(final_E))
|
905
935
|
return numpy.asarray(result)
|
@@ -173,7 +173,7 @@ class BackendCircuitCirq(BackendCircuit):
|
|
173
173
|
simulator = cirq.Simulator()
|
174
174
|
backend_result = simulator.simulate(program=self.circuit, param_resolver=self.resolver,
|
175
175
|
initial_state=initial_state)
|
176
|
-
return QubitWaveFunction.from_array(
|
176
|
+
return QubitWaveFunction.from_array(array=backend_result.final_state_vector, numbering=self.numbering)
|
177
177
|
|
178
178
|
def convert_measurements(self, backend_result: cirq.Result) -> QubitWaveFunction:
|
179
179
|
"""
|
@@ -186,18 +186,18 @@ class BackendCircuitCirq(BackendCircuit):
|
|
186
186
|
Returns
|
187
187
|
-------
|
188
188
|
QubitWaveFunction:
|
189
|
-
the result of sampling, as a tequila
|
189
|
+
the result of sampling, as a tequila QubitWaveFunction.
|
190
190
|
|
191
191
|
"""
|
192
192
|
assert (len(backend_result.measurements) == 1)
|
193
193
|
for key, value in backend_result.measurements.items():
|
194
|
-
counter = QubitWaveFunction()
|
194
|
+
counter = QubitWaveFunction(self.n_qubits, self.numbering)
|
195
195
|
for sample in value:
|
196
196
|
binary = BitString.from_array(array=sample.astype(int))
|
197
|
-
if binary in counter.
|
198
|
-
counter
|
197
|
+
if binary in counter.keys():
|
198
|
+
counter[binary] += 1
|
199
199
|
else:
|
200
|
-
counter
|
200
|
+
counter[binary] = 1
|
201
201
|
return counter
|
202
202
|
|
203
203
|
def do_sample(self, samples, circuit, *args, **kwargs) -> QubitWaveFunction:
|
@@ -439,7 +439,7 @@ class BackendCircuitPyquil(BackendCircuit):
|
|
439
439
|
if val > 0:
|
440
440
|
iprep += pyquil.gates.X(i)
|
441
441
|
backend_result = simulator.wavefunction(iprep + self.circuit, memory_map=self.resolver)
|
442
|
-
return QubitWaveFunction.from_array(
|
442
|
+
return QubitWaveFunction.from_array(array=backend_result.amplitudes, numbering=self.numbering)
|
443
443
|
|
444
444
|
def do_sample(self, samples, circuit, *args, **kwargs) -> QubitWaveFunction:
|
445
445
|
"""
|
@@ -495,7 +495,7 @@ class BackendCircuitPyquil(BackendCircuit):
|
|
495
495
|
listing.append(int(letter))
|
496
496
|
return listing
|
497
497
|
|
498
|
-
result = QubitWaveFunction()
|
498
|
+
result = QubitWaveFunction(self.n_qubits, self.numbering)
|
499
499
|
bit_dict = {}
|
500
500
|
for b in backend_result:
|
501
501
|
try:
|
@@ -505,7 +505,7 @@ class BackendCircuitPyquil(BackendCircuit):
|
|
505
505
|
|
506
506
|
for k, v in bit_dict.items():
|
507
507
|
arr = string_to_array(k)
|
508
|
-
result
|
508
|
+
result[BitString.from_array(arr)] = v
|
509
509
|
return result
|
510
510
|
|
511
511
|
def no_translation(self, abstract_circuit):
|