tequila-basic 1.9.7__py3-none-any.whl → 1.9.8__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/hamiltonian/paulis.py +4 -3
- tequila/quantumchemistry/encodings.py +2 -2
- tequila/quantumchemistry/orbital_optimizer.py +9 -2
- tequila/simulators/simulator_api.py +25 -9
- tequila/simulators/simulator_base.py +35 -12
- 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 +86 -49
- tequila/simulators/simulator_qiskit_gpu.py +9 -0
- tequila/simulators/simulator_qlm.py +3 -3
- tequila/simulators/simulator_qulacs.py +24 -19
- tequila/simulators/simulator_qulacs_gpu.py +6 -4
- tequila/simulators/simulator_symbolic.py +15 -23
- tequila/utils/bitstrings.py +8 -3
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +338 -238
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.8.dist-info}/METADATA +3 -8
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.8.dist-info}/RECORD +23 -22
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.8.dist-info}/WHEEL +1 -1
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.8.dist-info}/LICENSE +0 -0
- {tequila_basic-1.9.7.dist-info → tequila_basic-1.9.8.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,28 @@
|
|
1
1
|
from tequila.simulators.simulator_base import BackendCircuit, QCircuit, BackendExpectationValue
|
2
|
+
from tequila.utils.bitstrings import reverse_int_bits
|
2
3
|
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
|
3
4
|
from tequila import TequilaException, TequilaWarning
|
4
5
|
from tequila import BitString, BitNumbering, BitStringLSB
|
5
6
|
from tequila.utils.keymap import KeyMapRegisterToSubregister
|
6
7
|
from tequila.utils import to_float
|
7
|
-
|
8
|
+
from typing import Union
|
9
|
+
import warnings
|
10
|
+
import numpy as np
|
11
|
+
import qiskit, qiskit_aer, qiskit.providers.fake_provider
|
12
|
+
from qiskit import QuantumCircuit
|
8
13
|
|
9
|
-
HAS_NOISE=True
|
14
|
+
HAS_NOISE = True
|
10
15
|
try:
|
11
|
-
from qiskit_aer import noise as qiskitnoise
|
16
|
+
from qiskit_aer import noise as qiskitnoise, AerSimulator
|
12
17
|
except:
|
13
18
|
HAS_NOISE = False
|
14
19
|
|
15
|
-
HAS_IBMQ=True
|
20
|
+
HAS_IBMQ = True
|
16
21
|
try:
|
17
|
-
from
|
22
|
+
from qiskit_ibm_runtime import IBMBackend
|
18
23
|
except:
|
19
|
-
HAS_IBMQ=False
|
24
|
+
HAS_IBMQ = False
|
25
|
+
|
20
26
|
|
21
27
|
def get_bit_flip(p):
|
22
28
|
"""
|
@@ -70,16 +76,24 @@ gate_qubit_lookup = {
|
|
70
76
|
'multicontrol': 3
|
71
77
|
}
|
72
78
|
|
73
|
-
full_basis = ['x', 'y', 'z', 'id', 'u1', 'u2', 'u3', 'h','unitary','sx',
|
79
|
+
full_basis = ['x', 'y', 'z', 'id', 'u1', 'u2', 'u3', 'h', 'unitary', 'sx',
|
74
80
|
'cx', 'cy', 'cz', 'cu3', 'ccx']
|
75
81
|
|
82
|
+
|
76
83
|
def qiskit_device_dict():
|
77
|
-
|
78
|
-
|
79
|
-
|
84
|
+
# As of Quiskit Aer 0.15.0, backends() also returns legacy backends which are not AerSimulators that will be
|
85
|
+
# deprecated in the future
|
86
|
+
# TODO: Instead of building a dict with all backends just to search it, search directly with `get_backend`
|
87
|
+
# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.AerProvider.html#qiskit_aer.AerProvider.get_backend
|
88
|
+
devices = {backend.name.lower(): backend for backend in qiskit_aer.AerProvider().backends()
|
89
|
+
if isinstance(backend, AerSimulator)}
|
90
|
+
|
91
|
+
# FakeProvider has been removed, see https://github.com/Qiskit/qiskit/issues/10954
|
92
|
+
# devices.update({str(x).lower(): x for x in qiskit.test.mock.FakeProvider().backends()})
|
80
93
|
|
81
94
|
return devices
|
82
95
|
|
96
|
+
|
83
97
|
class TequilaQiskitException(TequilaException):
|
84
98
|
def __str__(self):
|
85
99
|
return "Error in qiskit backend:" + self.message
|
@@ -125,6 +139,8 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
125
139
|
transform a tequila NoiseModel into a qiskit noise model.
|
126
140
|
|
127
141
|
"""
|
142
|
+
STATEVECTOR_DEVICE_NAME = "aer_simulator_statevector"
|
143
|
+
|
128
144
|
compiler_arguments = {
|
129
145
|
"trotterized": True,
|
130
146
|
"swap": False,
|
@@ -145,7 +161,10 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
145
161
|
}
|
146
162
|
|
147
163
|
numbering = BitNumbering.LSB
|
148
|
-
|
164
|
+
|
165
|
+
supports_sampling_initialization = True
|
166
|
+
supports_generic_initialization = True
|
167
|
+
|
149
168
|
def __init__(self, abstract_circuit: QCircuit, variables, qubit_map=None, noise=None,
|
150
169
|
device=None, *args, **kwargs):
|
151
170
|
"""
|
@@ -188,8 +207,9 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
188
207
|
if qubit_map is None:
|
189
208
|
qubit_map = {q: i for i, q in enumerate(abstract_circuit.qubits)}
|
190
209
|
else:
|
191
|
-
warnings.warn("reveived custom qubit_map = {}\n"
|
192
|
-
"This is not fully integrated with qiskit and might result in unexpected behaviour"
|
210
|
+
warnings.warn(f"reveived custom qubit_map = {qubit_map}\n"
|
211
|
+
"This is not fully integrated with qiskit and might result in unexpected behaviour",
|
212
|
+
TequilaWarning)
|
193
213
|
|
194
214
|
n_qubits = max(qubit_map.values()) + 1
|
195
215
|
|
@@ -201,7 +221,7 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
201
221
|
|
202
222
|
self.classical_map = self.make_classical_map(qubit_map=self.qubit_map)
|
203
223
|
|
204
|
-
if noise
|
224
|
+
if noise is not None:
|
205
225
|
self.noise_lookup = {
|
206
226
|
'phase damp': qiskitnoise.phase_damping_error,
|
207
227
|
'amplitude damp': qiskitnoise.amplitude_damping_error,
|
@@ -211,12 +231,12 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
211
231
|
'depolarizing': qiskitnoise.depolarizing_error
|
212
232
|
}
|
213
233
|
|
214
|
-
if isinstance(noise, str):
|
234
|
+
if isinstance(noise, str): # string noise means "use the same noise as the device I tell you to get."
|
215
235
|
try:
|
216
236
|
self.check_device(noise)
|
217
237
|
self.noise_model = qiskitnoise.NoiseModel.from_backend(noise)
|
218
238
|
except TequilaQiskitException:
|
219
|
-
raise TequilaException("noise init from string requires that noise names a device. Got {}"
|
239
|
+
raise TequilaException(f"noise init from string requires that noise names a device. Got {noise}")
|
220
240
|
|
221
241
|
else:
|
222
242
|
self.noise_model = self.noise_model_converter(noise)
|
@@ -235,7 +255,7 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
235
255
|
qubit_map = super().make_qubit_map(qubits=qubits)
|
236
256
|
mapped_qubits = [q.number for q in qubit_map.values()]
|
237
257
|
for k, v in qubit_map.items():
|
238
|
-
qubit_map[k].instance = self.q
|
258
|
+
qubit_map[k].instance = self.q[v.number]
|
239
259
|
|
240
260
|
return qubit_map
|
241
261
|
|
@@ -247,6 +267,20 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
247
267
|
|
248
268
|
return classical_map
|
249
269
|
|
270
|
+
def add_state_init(self, circuit: QuantumCircuit, initial_state: Union[int, QubitWaveFunction]) -> QuantumCircuit:
|
271
|
+
if initial_state == 0:
|
272
|
+
return circuit
|
273
|
+
|
274
|
+
if isinstance(initial_state, QubitWaveFunction):
|
275
|
+
statevector = initial_state.to_array(self.numbering)
|
276
|
+
else:
|
277
|
+
statevector = np.zeros(2 ** self.n_qubits)
|
278
|
+
statevector[reverse_int_bits(initial_state, self.n_qubits)] = 1.0
|
279
|
+
|
280
|
+
init_circuit = qiskit.QuantumCircuit(self.q, self.c)
|
281
|
+
init_circuit.set_statevector(statevector)
|
282
|
+
return init_circuit.compose(circuit)
|
283
|
+
|
250
284
|
def do_simulate(self, variables, initial_state=0, *args, **kwargs) -> QubitWaveFunction:
|
251
285
|
"""
|
252
286
|
Helper function for performing simulation.
|
@@ -266,10 +300,12 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
266
300
|
"""
|
267
301
|
if self.noise_model is None:
|
268
302
|
if self.device is None:
|
269
|
-
qiskit_backend = self.retrieve_device(
|
303
|
+
qiskit_backend = self.retrieve_device(self.STATEVECTOR_DEVICE_NAME)
|
270
304
|
else:
|
271
305
|
if 'statevector' not in str(self.device):
|
272
|
-
raise TequilaException(
|
306
|
+
raise TequilaException(
|
307
|
+
'For simulation, only state vector simulators are supported; recieved device={}, you might have forgoten to set the samples keyword - e.g. (device={}, samples=1000). If not set, tequila assumes that full wavefunction simualtion is demanded which is not compatible with qiskit devices or fake devices except for device=statevector'.format(
|
308
|
+
self.device, self.device))
|
273
309
|
else:
|
274
310
|
qiskit_backend = self.retrieve_device(self.device)
|
275
311
|
else:
|
@@ -279,22 +315,18 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
279
315
|
if "optimization_level" in kwargs:
|
280
316
|
optimization_level = kwargs['optimization_level']
|
281
317
|
|
282
|
-
|
283
|
-
if initial_state != 0:
|
284
|
-
array = numpy.zeros(shape=[2 ** self.n_qubits])
|
285
|
-
i = BitStringLSB.from_binary(BitString.from_int(integer=initial_state, nbits=self.n_qubits).binary)
|
286
|
-
print(initial_state, " -> ", i)
|
287
|
-
array[i.integer] = 1.0
|
288
|
-
opts = {"initial_statevector": array}
|
318
|
+
circuit = self.circuit.assign_parameters(self.resolver)
|
289
319
|
|
290
|
-
circuit = self.circuit
|
320
|
+
circuit = self.add_state_init(circuit, initial_state)
|
291
321
|
|
292
|
-
|
322
|
+
circuit.save_statevector()
|
293
323
|
|
294
|
-
backend_result =
|
295
|
-
return QubitWaveFunction.from_array(arr=backend_result.get_statevector(circuit), numbering=self.numbering)
|
324
|
+
backend_result = qiskit_backend.run(circuit, optimization_level=optimization_level).result()
|
296
325
|
|
297
|
-
|
326
|
+
return QubitWaveFunction.from_array(array=backend_result.get_statevector(circuit).data, numbering=self.numbering)
|
327
|
+
|
328
|
+
def do_sample(self, circuit: qiskit.QuantumCircuit, samples: int, read_out_qubits, initial_state=0, *args,
|
329
|
+
**kwargs) -> QubitWaveFunction:
|
298
330
|
"""
|
299
331
|
Helper function for performing sampling.
|
300
332
|
Parameters
|
@@ -303,6 +335,8 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
303
335
|
the circuit from which to sample.
|
304
336
|
samples:
|
305
337
|
the number of samples to take.
|
338
|
+
initial_state:
|
339
|
+
initial state of the circuit
|
306
340
|
args
|
307
341
|
kwargs
|
308
342
|
|
@@ -319,17 +353,18 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
319
353
|
else:
|
320
354
|
qiskit_backend = self.retrieve_device(self.device)
|
321
355
|
|
322
|
-
if isinstance(qiskit_backend,
|
356
|
+
if isinstance(qiskit_backend, IBMBackend):
|
323
357
|
if self.noise_model is not None:
|
324
|
-
raise TequilaException(
|
325
|
-
|
358
|
+
raise TequilaException(
|
359
|
+
'Cannot combine backend {} with custom noise models.'.format(str(qiskit_backend)))
|
360
|
+
circuit = circuit.assign_parameters(self.resolver) # this is necessary in spite of qiskit "fixing" it
|
326
361
|
circuit = qiskit.transpile(circuit, qiskit_backend)
|
327
|
-
return self.convert_measurements(qiskit_backend.run(circuit,shots=samples,
|
328
|
-
|
362
|
+
return self.convert_measurements(qiskit_backend.run(circuit, shots=samples,
|
363
|
+
optimization_level=optimization_level),
|
329
364
|
target_qubits=read_out_qubits)
|
330
365
|
else:
|
331
|
-
if isinstance(qiskit_backend, qiskit.
|
332
|
-
circuit = circuit.
|
366
|
+
if isinstance(qiskit_backend, qiskit.providers.fake_provider.FakeBackend):
|
367
|
+
circuit = circuit.assign_parameters(self.resolver) # this is necessary in spite of qiskit "fixing" it
|
333
368
|
coupling_map = qiskit_backend.configuration().coupling_map
|
334
369
|
from_back = qiskitnoise.NoiseModel.from_backend(qiskit_backend)
|
335
370
|
if self.noise_model is not None:
|
@@ -343,23 +378,23 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
343
378
|
optimization_level=optimization_level
|
344
379
|
)
|
345
380
|
|
346
|
-
job=qiskit_backend.run(circuit, shots=samples)
|
347
|
-
return self.convert_measurements(job,target_qubits=read_out_qubits)
|
381
|
+
job = qiskit_backend.run(circuit, shots=samples)
|
382
|
+
return self.convert_measurements(job, target_qubits=read_out_qubits)
|
348
383
|
else:
|
349
384
|
if self.noise_model is not None:
|
350
385
|
qiskit_backend.set_options(noise_model=self.noise_model) # fits better with our methodology.
|
351
386
|
use_basis = full_basis
|
352
387
|
else:
|
353
388
|
use_basis = qiskit_backend.configuration().basis_gates
|
354
|
-
circuit = circuit.
|
389
|
+
circuit = circuit.assign_parameters(self.resolver) # this is necessary -- see qiskit-aer issue 1346
|
390
|
+
circuit = self.add_state_init(circuit, initial_state)
|
355
391
|
circuit = qiskit.transpile(circuit, backend=qiskit_backend,
|
356
392
|
basis_gates=use_basis,
|
357
393
|
optimization_level=optimization_level
|
358
394
|
)
|
359
395
|
|
360
396
|
job = qiskit_backend.run(circuit, shots=samples)
|
361
|
-
return self.convert_measurements(job,
|
362
|
-
target_qubits=read_out_qubits)
|
397
|
+
return self.convert_measurements(job, target_qubits=read_out_qubits)
|
363
398
|
|
364
399
|
def convert_measurements(self, backend_result, target_qubits=None) -> QubitWaveFunction:
|
365
400
|
"""
|
@@ -374,16 +409,17 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
374
409
|
measurements converted into wave function form.
|
375
410
|
"""
|
376
411
|
qiskit_counts = backend_result.result().get_counts()
|
377
|
-
result = QubitWaveFunction()
|
412
|
+
result = QubitWaveFunction(self.n_qubits, self.numbering)
|
378
413
|
# todo there are faster ways
|
379
414
|
for k, v in qiskit_counts.items():
|
380
|
-
|
381
|
-
|
415
|
+
# Qiskit uses LSB bitstrings, but from_binary expects MSB
|
416
|
+
converted_key = BitString.from_binary(k[::-1])
|
417
|
+
result[converted_key] = v
|
382
418
|
if target_qubits is not None:
|
383
419
|
mapped_target = [self.qubit_map[q].number for q in target_qubits]
|
384
420
|
mapped_full = [self.qubit_map[q].number for q in self.abstract_qubits]
|
385
421
|
keymap = KeyMapRegisterToSubregister(subregister=mapped_target, register=mapped_full)
|
386
|
-
result =
|
422
|
+
result = QubitWaveFunction.from_wavefunction(result, keymap, n_qubits=len(target_qubits))
|
387
423
|
|
388
424
|
return result
|
389
425
|
|
@@ -436,7 +472,8 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
436
472
|
par = float(gate.parameter)
|
437
473
|
if gate.is_controlled():
|
438
474
|
if len(gate.control) > 2:
|
439
|
-
raise TequilaQiskitException(
|
475
|
+
raise TequilaQiskitException(
|
476
|
+
"multi-controls beyond 2 not yet supported for the qiskit backend. Gate was:\n{}".format(gate))
|
440
477
|
ops[1](circuit)(par, self.qubit(gate.control[0]), self.qubit(gate.target[0]))
|
441
478
|
else:
|
442
479
|
ops[0](circuit)(par, self.qubit(gate.target[0]))
|
@@ -590,7 +627,7 @@ class BackendCircuitQiskit(BackendCircuit):
|
|
590
627
|
if device is None:
|
591
628
|
return
|
592
629
|
|
593
|
-
elif isinstance(device,qiskit.providers.Backend):
|
630
|
+
elif isinstance(device, qiskit.providers.Backend):
|
594
631
|
return
|
595
632
|
|
596
633
|
elif isinstance(device, dict):
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from tequila.simulators.simulator_qiskit import BackendCircuitQiskit, BackendExpectationValueQiskit
|
2
|
+
|
3
|
+
|
4
|
+
class BackendCircuitQiskitGpu(BackendCircuitQiskit):
|
5
|
+
STATEVECTOR_DEVICE_NAME = "aer_simulator_statevector_gpu"
|
6
|
+
|
7
|
+
|
8
|
+
class BackendExpectationValueQiskitGpu(BackendExpectationValueQiskit):
|
9
|
+
BackendCircuitType = BackendCircuitQiskitGpu
|
@@ -395,10 +395,10 @@ class BackendCircuitQLM(BackendCircuit):
|
|
395
395
|
if MY_QLM:
|
396
396
|
result = PyLinalg().submit(job)
|
397
397
|
statevector = get_statevector(result)
|
398
|
-
return QubitWaveFunction.from_array(
|
398
|
+
return QubitWaveFunction.from_array(array=statevector, numbering=self.numbering)
|
399
399
|
|
400
400
|
result = LinAlg().submit(job)
|
401
|
-
return QubitWaveFunction.from_array(
|
401
|
+
return QubitWaveFunction.from_array(array=result.statevector, numbering=self.numbering)
|
402
402
|
|
403
403
|
def update_variables(self, variables):
|
404
404
|
"""
|
@@ -431,7 +431,7 @@ class BackendCircuitQLM(BackendCircuit):
|
|
431
431
|
QubitWaveFunction:
|
432
432
|
measurements converted into wave function form.
|
433
433
|
"""
|
434
|
-
result = QubitWaveFunction()
|
434
|
+
result = QubitWaveFunction(self.n_qubits, self.numbering)
|
435
435
|
shots = int(backend_result.meta_data["nbshots"])
|
436
436
|
nbits = backend_result[0].qregs[0].length
|
437
437
|
for sample in backend_result:
|
@@ -1,9 +1,11 @@
|
|
1
|
+
from typing import Union
|
2
|
+
|
1
3
|
import qulacs
|
2
4
|
import numbers, numpy
|
3
5
|
import warnings
|
4
6
|
|
5
7
|
from tequila import TequilaException, TequilaWarning
|
6
|
-
from tequila.utils.bitstrings import BitNumbering, BitString, BitStringLSB
|
8
|
+
from tequila.utils.bitstrings import BitNumbering, BitString, BitStringLSB, reverse_int_bits
|
7
9
|
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
|
8
10
|
from tequila.simulators.simulator_base import BackendCircuit, BackendExpectationValue, QCircuit, change_basis
|
9
11
|
from tequila.utils.keymap import KeyMapRegisterToSubregister
|
@@ -63,6 +65,11 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
63
65
|
|
64
66
|
numbering = BitNumbering.LSB
|
65
67
|
|
68
|
+
quantum_state_class = qulacs.QuantumState
|
69
|
+
|
70
|
+
supports_sampling_initialization = True
|
71
|
+
supports_generic_initialization = True
|
72
|
+
|
66
73
|
def __init__(self, abstract_circuit, noise=None, *args, **kwargs):
|
67
74
|
"""
|
68
75
|
|
@@ -110,10 +117,17 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
110
117
|
|
111
118
|
self.circuit=self.add_noise_to_circuit(noise)
|
112
119
|
|
113
|
-
def initialize_state(self, n_qubits:int=None) -> qulacs.QuantumState:
|
120
|
+
def initialize_state(self, n_qubits: int = None, initial_state: Union[int, QubitWaveFunction] = None) -> qulacs.QuantumState:
|
114
121
|
if n_qubits is None:
|
115
122
|
n_qubits = self.n_qubits
|
116
|
-
|
123
|
+
|
124
|
+
state = self.quantum_state_class(n_qubits)
|
125
|
+
if isinstance(initial_state, int):
|
126
|
+
state.set_computational_basis(reverse_int_bits(initial_state, self.n_qubits))
|
127
|
+
elif isinstance(initial_state, QubitWaveFunction):
|
128
|
+
state.load(initial_state.to_array(self.numbering))
|
129
|
+
|
130
|
+
return state
|
117
131
|
|
118
132
|
def update_variables(self, variables):
|
119
133
|
"""
|
@@ -130,7 +144,7 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
130
144
|
for k, angle in enumerate(self.variables):
|
131
145
|
self.circuit.set_parameter(k, angle(variables))
|
132
146
|
|
133
|
-
def do_simulate(self, variables, initial_state, *args, **kwargs):
|
147
|
+
def do_simulate(self, variables, initial_state: Union[int, QubitWaveFunction], *args, **kwargs):
|
134
148
|
"""
|
135
149
|
Helper function to perform simulation.
|
136
150
|
|
@@ -148,12 +162,10 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
148
162
|
QubitWaveFunction:
|
149
163
|
QubitWaveFunction representing result of the simulation.
|
150
164
|
"""
|
151
|
-
state = self.initialize_state(self.n_qubits)
|
152
|
-
lsb = BitStringLSB.from_int(initial_state, nbits=self.n_qubits)
|
153
|
-
state.set_computational_basis(BitString.from_binary(lsb.binary).integer)
|
165
|
+
state = self.initialize_state(self.n_qubits, initial_state)
|
154
166
|
self.circuit.update_quantum_state(state)
|
155
167
|
|
156
|
-
wfn = QubitWaveFunction.from_array(
|
168
|
+
wfn = QubitWaveFunction.from_array(array=state.get_vector(), numbering=self.numbering)
|
157
169
|
return wfn
|
158
170
|
|
159
171
|
def convert_measurements(self, backend_result, target_qubits=None) -> QubitWaveFunction:
|
@@ -170,22 +182,17 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
170
182
|
results transformed to tequila native QubitWaveFunction
|
171
183
|
"""
|
172
184
|
|
173
|
-
result = QubitWaveFunction()
|
185
|
+
result = QubitWaveFunction(self.n_qubits, self.numbering)
|
174
186
|
# todo there are faster ways
|
175
187
|
|
176
|
-
|
177
188
|
for k in backend_result:
|
178
|
-
|
179
|
-
if converted_key in result._state:
|
180
|
-
result._state[converted_key] += 1
|
181
|
-
else:
|
182
|
-
result._state[converted_key] = 1
|
189
|
+
result[k] += 1
|
183
190
|
|
184
191
|
if target_qubits is not None:
|
185
192
|
mapped_target = [self.qubit_map[q].number for q in target_qubits]
|
186
193
|
mapped_full = [self.qubit_map[q].number for q in self.abstract_qubits]
|
187
194
|
keymap = KeyMapRegisterToSubregister(subregister=mapped_target, register=mapped_full)
|
188
|
-
result =
|
195
|
+
result = QubitWaveFunction.from_wavefunction(result, keymap, n_qubits=len(target_qubits))
|
189
196
|
|
190
197
|
return result
|
191
198
|
|
@@ -211,9 +218,7 @@ class BackendCircuitQulacs(BackendCircuit):
|
|
211
218
|
QubitWaveFunction:
|
212
219
|
the results of sampling, as a Qubit Wave Function.
|
213
220
|
"""
|
214
|
-
state = self.initialize_state(self.n_qubits)
|
215
|
-
lsb = BitStringLSB.from_int(initial_state, nbits=self.n_qubits)
|
216
|
-
state.set_computational_basis(BitString.from_binary(lsb.binary).integer)
|
221
|
+
state = self.initialize_state(self.n_qubits, initial_state)
|
217
222
|
circuit.update_quantum_state(state)
|
218
223
|
sampled = state.sampling(samples)
|
219
224
|
return self.convert_measurements(backend_result=sampled, target_qubits=self.measurements)
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import qulacs
|
2
|
+
from qulacs_core import QuantumStateGpu
|
3
|
+
|
2
4
|
from tequila import TequilaException
|
3
5
|
from tequila.simulators.simulator_qulacs import BackendCircuitQulacs, BackendExpectationValueQulacs
|
4
6
|
|
7
|
+
|
5
8
|
class TequilaQulacsGpuException(TequilaException):
|
6
9
|
def __str__(self):
|
7
10
|
return "Error in qulacs gpu backend:" + self.message
|
8
11
|
|
12
|
+
|
9
13
|
class BackendCircuitQulacsGpu(BackendCircuitQulacs):
|
10
|
-
|
11
|
-
|
12
|
-
n_qubits = self.n_qubits
|
13
|
-
return qulacs.QuantumStateGpu(n_qubits)
|
14
|
+
quantum_state_class = QuantumStateGpu
|
15
|
+
|
14
16
|
|
15
17
|
class BackendExpectationValueQulacsGpu(BackendExpectationValueQulacs):
|
16
18
|
BackendCircuitType = BackendCircuitQulacsGpu
|
@@ -42,37 +42,30 @@ class BackendCircuitSymbolic(BackendCircuit):
|
|
42
42
|
|
43
43
|
@classmethod
|
44
44
|
def apply_gate(cls, state: QubitWaveFunction, gate: QGate, qubits: dict, variables) -> QubitWaveFunction:
|
45
|
-
result = QubitWaveFunction()
|
46
45
|
n_qubits = len(qubits.keys())
|
46
|
+
result = sympy.Integer(1) * QubitWaveFunction(n_qubits)
|
47
47
|
for s, v in state.items():
|
48
|
-
|
49
|
-
result += v * cls.apply_on_standard_basis(gate=gate, basisfunction=s, qubits=qubits, variables=variables)
|
48
|
+
result += v * cls.apply_on_standard_basis(gate=gate, basis_state=s, qubits=qubits, variables=variables)
|
50
49
|
return result
|
51
50
|
|
52
51
|
@classmethod
|
53
|
-
def apply_on_standard_basis(cls, gate: QGate,
|
54
|
-
|
55
|
-
basis_array =
|
56
|
-
if gate.is_controlled():
|
57
|
-
|
58
|
-
check = [basis_array[qubits[c]] == 1 for c in gate.control]
|
59
|
-
for c in check:
|
60
|
-
if not c:
|
61
|
-
do_apply = False
|
62
|
-
if not do_apply:
|
63
|
-
return QubitWaveFunction.from_int(basisfunction)
|
52
|
+
def apply_on_standard_basis(cls, gate: QGate, basis_state: BitString, qubits:dict, variables) -> QubitWaveFunction:
|
53
|
+
n_qubits = len(qubits.keys())
|
54
|
+
basis_array = basis_state.array
|
55
|
+
if gate.is_controlled() and not all(basis_array[qubits[c]] == 1 for c in gate.control):
|
56
|
+
return QubitWaveFunction.from_basis_state(n_qubits, basis_state)
|
64
57
|
|
65
58
|
if len(gate.target) > 1:
|
66
59
|
raise Exception("Multi-targets not supported for symbolic simulators")
|
67
60
|
|
68
|
-
result = QubitWaveFunction()
|
61
|
+
result = sympy.Integer(1) * QubitWaveFunction(n_qubits)
|
69
62
|
for tt in gate.target:
|
70
63
|
t = qubits[tt]
|
71
64
|
qt = basis_array[t]
|
72
65
|
a_array = copy.deepcopy(basis_array)
|
73
66
|
a_array[t] = (a_array[t] + 1) % 2
|
74
|
-
current_state = QubitWaveFunction.
|
75
|
-
altered_state = QubitWaveFunction.
|
67
|
+
current_state = QubitWaveFunction.from_basis_state(n_qubits, basis_state)
|
68
|
+
altered_state = QubitWaveFunction.from_basis_state(n_qubits, BitString.from_array(a_array))
|
76
69
|
|
77
70
|
fac1 = None
|
78
71
|
fac2 = None
|
@@ -115,22 +108,21 @@ class BackendCircuitSymbolic(BackendCircuit):
|
|
115
108
|
count = 0
|
116
109
|
for q in self.abstract_circuit.qubits:
|
117
110
|
qubits[q] = count
|
118
|
-
count +=1
|
111
|
+
count += 1
|
119
112
|
|
120
113
|
n_qubits = len(self.abstract_circuit.qubits)
|
121
114
|
|
122
115
|
if initial_state is None:
|
123
|
-
initial_state =
|
124
|
-
|
125
|
-
initial_state = QubitWaveFunction.from_int(initial_state, n_qubits=n_qubits)
|
116
|
+
initial_state = 0
|
117
|
+
initial_state = QubitWaveFunction.from_basis_state(n_qubits, initial_state)
|
126
118
|
|
127
119
|
result = initial_state
|
128
120
|
for g in self.abstract_circuit.gates:
|
129
121
|
result = self.apply_gate(state=result, gate=g, qubits=qubits, variables=variables)
|
130
122
|
|
131
|
-
wfn = QubitWaveFunction()
|
123
|
+
wfn = QubitWaveFunction(n_qubits)
|
132
124
|
if self.convert_to_numpy:
|
133
|
-
for k,v in result.items():
|
125
|
+
for k, v in result.items():
|
134
126
|
wfn[k] = complex(v)
|
135
127
|
else:
|
136
128
|
wfn = result
|
tequila/utils/bitstrings.py
CHANGED
@@ -178,7 +178,7 @@ class BitStringLSB(BitString):
|
|
178
178
|
return BitNumbering.LSB
|
179
179
|
|
180
180
|
|
181
|
-
def
|
181
|
+
def reverse_int_bits(x: int, nbits: int) -> int:
|
182
182
|
if nbits is None:
|
183
183
|
nbits = x.bit_length()
|
184
184
|
assert nbits <= 32
|
@@ -192,8 +192,13 @@ def _reverse_int_bits(x: int, nbits: int) -> int:
|
|
192
192
|
|
193
193
|
|
194
194
|
def initialize_bitstring(integer: int, nbits: int = None, numbering_in: BitNumbering = BitNumbering.MSB,
|
195
|
-
numbering_out: BitNumbering =
|
196
|
-
|
195
|
+
numbering_out: BitNumbering = None):
|
196
|
+
if numbering_out is None:
|
197
|
+
numbering_out = numbering_in
|
198
|
+
|
199
|
+
if numbering_in != numbering_out:
|
200
|
+
integer = reverse_int_bits(integer, nbits)
|
201
|
+
|
197
202
|
if numbering_out == BitNumbering.MSB:
|
198
203
|
return BitString.from_int(integer=integer, nbits=nbits)
|
199
204
|
else:
|
tequila/version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "1.9.
|
1
|
+
__version__ = "1.9.8"
|
2
2
|
__author__ = "Tequila Developers "
|