The following function performs modular inversion of a number:
u = qrisp.QuantumFloat(n)
u[:] = p
v = qrisp.QuantumFloat(n)
v[:] = x
r = qrisp.QuantumModulus(2*p)
r[:] = 0
s = qrisp.QuantumModulus(2*p)
s[:] = 1
for _ in range(2*n):
swap = qrisp.QuantumBool()
swap[:] = True
with v == 0 as v_is_zero:
qrisp.cyclic_shift(r)
v_is_zero.flip()
swap.flip()
with q_eval_expr_1(u, v):
qrisp.swap(u, v)
qrisp.swap(r, s)
swap.flip()
with q_eval_expr_2(u, v):
v -= u
s += r
with qrisp.invert():
qrisp.cyclic_shift(v)
qrisp.cyclic_shift(r)
with swap:
qrisp.swap(u, v)
qrisp.swap(r, s)
swap.uncompute()
larger = qrisp.QuantumBool()
r.__class__ = qrisp.QuantumFloat
larger[:] = r > p
r.__class__ = qrisp.QuantumModulus
with larger:
r-=p
inv = qrisp.QuantumModulus(2*p) #maybe just use a quantum float
inv[:] = p-r
return u,v,r,s,inv
It works perfectly when the input is classical:
t = qrisp.QuantumModulus(p)
t[:] = 2
to_montgomery(t, p)
print(t)
res = kaliski_swaps_check(t, p, p.bit_length())
qrisp.multi_measurement(res)
which produces the output {(1, 0, 1, 5, 4),1.0} , as expected. However when fetched with a superposition, the following code produces an error:
t = qrisp.QuantumModulus(p)
t[:] = 2
qrisp.h(t[1])
to_montgomery(t, p)
#print(t)
res = kaliski_swaps_check(t, p, p.bit_length())
qrisp.multi_measurement(res)
ERROR:
{
"name": "ValueError",
"message": "negative row index found",
"stack": "---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[66], line 1
----> 1 qrisp.multi_measurement(res)
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\misc\\utility.py:735, in multi_measurement(qv_list, shots, backend)
731 compiled_qc.measure(qubits, cl_reg)
733 # counts = execute(qs_temp, backend, basis_gates = basis_gates,
734 # noise_model = noise_model, shots = shots).result().get_counts()
--> 735 counts = backend.run(compiled_qc, shots)
736 counts = {k: counts[k] for k in sorted(counts)}
738 # Convert the labeling bistrings of counts into list of labels
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\default_backend.py:37, in DefaultBackend.run(self, qc, shots, token)
35 def run(self, qc, shots, token = \"\"):
---> 37 return run(qc, shots, token)
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\simulator.py:156, in run(qc, shots, token, iqs, insert_reset)
150 iqs.disentangle(qubit_indices[0])
152 # If the operation is unitary, we apply this unitary on to the required
153 # qubit indices
154 else:
--> 156 iqs.apply_operation(instr.op, qubit_indices)
158 # If all measurements have been performed, break
159 if measurement_counter == measurement_amount:
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\quantum_state.py:78, in QuantumState.apply_operation(self, operation, qubits)
75 unitary = operation.get_unitary()
77 # Apply the matrix
---> 78 entangled_factor.apply_matrix(unitary, qubits)
80 if entangled_factor.tensor_array.data.dtype == xp.dtype(\"O\"):
81 return
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\tensor_factor.py:94, in TensorFactor.apply_matrix(self, matrix, qubits)
89 reshaped_tensor_array = self.tensor_array.reshape(
90 (matrix.shape[0], 2**self.n // matrix.shape[0])
91 )
93 # Apply matrix
---> 94 self.tensor_array = tensordot(
95 matrix, reshaped_tensor_array, axes=(1, 0), contract_sparsity_threshold=0.05
96 ).reshape(2**self.n)
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\bi_arrays.py:1356, in tensordot(a, b, axes, contract_sparsity_threshold)
1352 mp_wrapper()
1354 return res
-> 1356 return a.contract(b, axes[0], axes[1])
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\bi_arrays.py:575, in SparseBiArray.contract(self, other, axes_self, axes_other)
573 res.thread.start()
574 else:
--> 575 mp_wrapper()
577 return res
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\bi_arrays.py:542, in SparseBiArray.contract..mp_wrapper()
537 def mp_wrapper():
538 # Build up sparse matrices
539 sr_matrix_self = self.build_sr_matrix(
540 (contraction_size, self.size // contraction_size), transpose=True
541 )
--> 542 sr_matrix_other = other.build_sr_matrix(
543 (contraction_size, other.size // contraction_size)
544 )
546 # Perform sparse matrix multiplication
548 res_sr_matrix = sparse_matrix_mult(sr_matrix_self, sr_matrix_other)
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\qrisp\\simulator\\bi_arrays.py:426, in SparseBiArray.build_sr_matrix(self, shape, transpose)
424 # Create sparse matrix
425 if not transpose:
--> 426 res = coo_array((self.data, (row, col)), shape=shape)
427 else:
428 res = coo_array((self.data, (col, row)), shape=shape[::-1])
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\scipy\\sparse\\_coo.py:204, in _coo_base.__init__(self, arg1, shape, dtype, copy)
201 if dtype is not None:
202 self.data = self.data.astype(dtype, copy=False)
--> 204 self._check()
File c:\\Users\\dpolimen\\anaconda3\\envs\\venvABqiskitprovider\\lib\\site-packages\\scipy\\sparse\\_coo.py:295, in _coo_base._check(self)
293 raise ValueError('column index exceeds matrix dimensions')
294 if self.row.min() < 0:
--> 295 raise ValueError('negative row index found')
296 if self.col.min() < 0:
297 raise ValueError('negative column index found')
ValueError: negative row index found"
}
Note that the function to_montgomery is just an in-place multiplication.
The following function performs modular inversion of a number:
It works perfectly when the input is classical:
which produces the output {(1, 0, 1, 5, 4),1.0} , as expected. However when fetched with a superposition, the following code produces an error:
ERROR:
Note that the function
to_montgomery
is just an in-place multiplication.