tequila-basic 1.9.6__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.
@@ -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
- import qiskit, numpy, warnings
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 qiskit.providers.ibmq import IBMQBackend
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
- devices = {}
78
- devices.update({str(x).lower():x for x in qiskit.Aer.backends()})
79
- devices.update({str(x).lower():x for x in qiskit.test.mock.FakeProvider().backends()})
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".format(qubit_map), TequilaWarning)
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 != None:
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): #string noise means "use the same noise as the device I tell you to get."
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 {}".format(noise))
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 [v.number]
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('statevector_simulator')
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('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(self.device, self.device))
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
- opts = {}
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.bind_parameters(self.resolver)
320
+ circuit = self.add_state_init(circuit, initial_state)
291
321
 
292
- qiskit_job = qiskit_backend.run(circuit,optimization_level=optimization_level,**opts)
322
+ circuit.save_statevector()
293
323
 
294
- backend_result = qiskit_job.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
- def do_sample(self, circuit: qiskit.QuantumCircuit, samples: int, read_out_qubits, *args, **kwargs) -> QubitWaveFunction:
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,IBMQBackend):
356
+ if isinstance(qiskit_backend, IBMBackend):
323
357
  if self.noise_model is not None:
324
- raise TequilaException('Cannot combine backend {} with custom noise models.'.format(str(qiskit_backend)))
325
- circuit = circuit.bind_parameters(self.resolver) # this is necessary in spite of qiskit "fixing" it
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
- optimization_level=optimization_level),
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.test.mock.FakeBackend):
332
- circuit = circuit.bind_parameters(self.resolver) # this is necessary in spite of qiskit "fixing" it
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.bind_parameters(self.resolver) # this is necessary -- see qiskit-aer issue 1346
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
- converted_key = BitString.from_bitstring(other=BitStringLSB.from_binary(binary=k))
381
- result._state[converted_key] = v
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 = result.apply_keymap(keymap=keymap)
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("multi-controls beyond 2 not yet supported for the qiskit backend. Gate was:\n{}".format(gate) )
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(arr=statevector, numbering=self.numbering)
398
+ return QubitWaveFunction.from_array(array=statevector, numbering=self.numbering)
399
399
 
400
400
  result = LinAlg().submit(job)
401
- return QubitWaveFunction.from_array(arr=result.statevector, numbering=self.numbering)
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
- return qulacs.QuantumState(n_qubits)
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(arr=state.get_vector(), numbering=self.numbering)
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
- converted_key = BitString.from_binary(BitStringLSB.from_int(integer=k, nbits=self.n_qubits).binary)
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 = result.apply_keymap(keymap=keymap)
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
- def initialize_state(self, n_qubits:int=None) -> qulacs.QuantumState:
11
- if n_qubits is None:
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
- s.nbits = n_qubits
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, basisfunction: BitString, qubits:dict, variables) -> QubitWaveFunction:
54
-
55
- basis_array = basisfunction.array
56
- if gate.is_controlled():
57
- do_apply = True
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.from_int(basisfunction)
75
- altered_state = QubitWaveFunction.from_int(BitString.from_array(a_array))
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 = QubitWaveFunction.from_int(i=0, n_qubits=n_qubits)
124
- elif isinstance(initial_state, int):
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
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
  from typing import List
3
3
  from functools import total_ordering
4
+ from math import ceil, log2
4
5
 
5
6
 
6
7
  class BitNumbering(Enum):
@@ -35,7 +36,7 @@ class BitString:
35
36
 
36
37
  def update_nbits(self):
37
38
  current = self.nbits
38
- min_needed = len(format(self._value, 'b'))
39
+ min_needed = ceil(log2(self._value + 1))
39
40
  self._nbits = max(current, min_needed)
40
41
  return self
41
42
 
@@ -177,15 +178,28 @@ class BitStringLSB(BitString):
177
178
  return BitNumbering.LSB
178
179
 
179
180
 
181
+ def reverse_int_bits(x: int, nbits: int) -> int:
182
+ if nbits is None:
183
+ nbits = x.bit_length()
184
+ assert nbits <= 32
185
+
186
+ x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1)
187
+ x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2)
188
+ x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4)
189
+ x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8)
190
+ x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
191
+ return x >> (32 - nbits)
192
+
193
+
180
194
  def initialize_bitstring(integer: int, nbits: int = None, numbering_in: BitNumbering = BitNumbering.MSB,
181
- numbering_out: BitNumbering = BitNumbering.MSB):
182
- if numbering_in == BitNumbering.MSB:
183
- if numbering_out == BitNumbering.MSB:
184
- return BitString.from_int(integer=integer, nbits=nbits)
185
- else:
186
- return BitString.from_binary(binary=BitStringLSB.from_int(integer=integer, nbits=nbits).binary, nbits=nbits)
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
+
202
+ if numbering_out == BitNumbering.MSB:
203
+ return BitString.from_int(integer=integer, nbits=nbits)
187
204
  else:
188
- if numbering_out == BitNumbering.LSB:
189
- return BitStringLSB.from_int(integer=integer, nbits=nbits)
190
- else:
191
- return BitStringLSB.from_binary(binary=BitString.from_int(integer=integer, nbits=nbits).binary, nbits=nbits)
205
+ return BitStringLSB.from_int(integer=integer, nbits=nbits)
tequila/version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "1.9.6"
1
+ __version__ = "1.9.8"
2
2
  __author__ = "Tequila Developers "