eclipse-qrisp / Qrisp

Qrisp - a framework for high-level programming of Quantum computers
https://www.qrisp.eu/
Eclipse Public License 2.0
83 stars 23 forks source link

Simulation error: negative row index found #45

Open diehoq opened 4 months ago

diehoq commented 4 months ago

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.