Open renatomello opened 7 months ago
Thanks @renatomello for noting down this error.
From the call stack, it seems the way quimb is invoked has some issue. Particularly, the args provided might not be compatible. @Vinitha-balachandran Can we take a look and prepare a PR for the fix?
@liweintu Sure, will check.
@renatomello computation settings has to be given before the set_backend. It was a mistake in doc. And, for your code with the import c= Circuit(2) instead of c = qibo.Circuit(2). There was no error when I run the code with this fix. I will update the doc.
@renatomello computation settings has to be given before the set_backend. It was a mistake in doc. And, for your code with the import c= Circuit(2) instead of c = qibo.Circuit(2). There was no error when I run the code with this fix. I will update the doc.
The problem was that platform
should've been cutensornet
instead of qutensornet
.
If I try to print the result object instead of calling the .state()
method, another error appears:
In [17]: from qibo import Circuit, gates, set_backend
...:
...: computation_settings = {
...: "MPI_enabled": False,
...: "MPS_enabled": False,
...: "NCCL_enabled": False,
...: "expectation_enabled": False,
...: }
...:
...: # Set the quimb backend
...: set_backend(
...: backend="qibotn", platform="cutensornet", runcard=computation_settings
...: )
...:
...: # Construct the circuit with two qubits
...: c = Circuit(2)
...:
...: # Apply Hadamard gates on first and second qubit
...: c.add(gates.H(0))
...: c.add(gates.H(1))
...: c.add(gates.CZ(0, 1))
...:
...: # Execute the circuit and obtain the final state
...: result = c()
...:
...: # Print the final state
...: print(result)
[Qibo 0.2.7|INFO|2024-03-28 10:44:57]: Using qibotn (cutensornet) backend on /CPU:0
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[17], line 27
24 result = c()
26 # Print the final state
---> 27 print(result)
File ~/.local/lib/python3.10/site-packages/qibo/result.py:108, in QuantumState.__str__(self)
107 def __str__(self):
--> 108 return self.symbolic()
File ~/.local/lib/python3.10/site-packages/qibo/result.py:60, in QuantumState.symbolic(self, decimals, cutoff, max_terms)
56 terms = self.backend.calculate_symbolic_density_matrix(
57 self._state, self.nqubits, decimals, cutoff, max_terms
58 )
59 else:
---> 60 terms = self.backend.calculate_symbolic(
61 self._state, self.nqubits, decimals, cutoff, max_terms
62 )
63 return " + ".join(terms)
File ~/.local/lib/python3.10/site-packages/qibo/backends/numpy.py:578, in NumpyBackend.calculate_symbolic(self, state, nqubits, decimals, cutoff, max_terms)
576 terms = []
577 for i in np.nonzero(state)[0]:
--> 578 b = bin(i)[2:].zfill(nqubits)
579 if np.abs(state[i]) >= cutoff:
580 x = np.round(state[i], decimals)
TypeError: 'ndarray' object cannot be interpreted as an integer
Also, calling the state
method kind of defeats the purpose of running circuits as MPS. Is there a way to recover the MPS itself from the Circuit Result object?
About the last two comments, primarily we were interested to have one to one comparison of state vector and tensor network method. So, at present we are converting the mps (or tensor ) form to dense vector. Sure, we will consider updating it to recover also in the MPS format.
I tried to run the example inside the
doc
file of this repo and got this errorfrom qibo import Circuit, gates, set_backend # Set the quimb backend set_backend( backend="qibotn", platform="qutensornet", runcard=computation_settings ) # Set the runcard computation_settings = { "MPI_enabled": False, "MPS_enabled": False, "NCCL_enabled": False, "expectation_enabled": False, } # Construct the circuit with two qubits c = Circuit(2) # Apply Hadamard gates on first and second qubit c.add(gates.H(0)) c.add(gates.H(1)) # Execute the circuit and obtain the final state result = c() # Print the final state print(result.state())
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[12], line 24 21 c.add(qibo.gates.H(1)) 23 # Execute the circuit and obtain the final state ---> 24 result = c() 26 # Print the final state 27 print(result.state()) File ~/.local/lib/python3.10/site-packages/qibo/models/circuit.py:1117, in Circuit.__call__(self, initial_state, nshots) 1115 def __call__(self, initial_state=None, nshots=1000): 1116 """Equivalent to ``circuit.execute``.""" -> 1117 return self.execute(initial_state=initial_state, nshots=nshots) File ~/.local/lib/python3.10/site-packages/qibo/models/circuit.py:1113, in Circuit.execute(self, initial_state, nshots) 1109 return GlobalBackend().execute_distributed_circuit( 1110 self, initial_state, nshots 1111 ) 1112 else: -> 1113 return GlobalBackend().execute_circuit(self, initial_state, nshots) File ~/.local/lib/python3.10/site-packages/qibotn/backends/quimb.py:78, in QuimbBackend.execute_circuit(self, circuit, initial_state, nshots, return_array) 73 if self.expectation_enabled == True: 74 raise_error( 75 NotImplementedError, "QiboTN quimb backend cannot support expectation" 76 ) ---> 78 state = eval.dense_vector_tn_qu( 79 circuit.to_qasm(), initial_state, self.mps_opts, backend="numpy" 80 ) 82 if return_array: 83 return state.flatten() File ~/.local/lib/python3.10/site-packages/qibotn/eval_qu.py:39, in dense_vector_tn_qu(qasm, initial_state, mps_opts, backend) 36 initial_state = init_state_tn(nqubits, initial_state) 38 circ_cls = qtn.circuit.CircuitMPS if mps_opts else qtn.circuit.Circuit ---> 39 circ_quimb = circ_cls.from_openqasm2_str( 40 qasm, psi0=initial_state, gate_opts=mps_opts 41 ) 43 interim = circ_quimb.psi.full_simplify(seq="DRC") 44 amplitudes = interim.to_dense(backend=backend) File ~/.local/lib/python3.10/site-packages/quimb/tensor/circuit.py:1499, in Circuit.from_openqasm2_str(cls, contents, **circuit_opts) 1497 """Generate a ``Circuit`` instance from an OpenQASM 2.0 string.""" 1498 info = parse_openqasm2_str(contents) -> 1499 qc = cls(info["n"], **circuit_opts) 1500 qc.apply_gates(info["gates"]) 1501 return qc File ~/.local/lib/python3.10/site-packages/quimb/tensor/circuit.py:1438, in Circuit.__init__(self, N, psi0, gate_opts, gate_contract, gate_propagate_tags, tags, psi0_dtype, psi0_tag, bra_site_ind_id) 1435 for tag in tags: 1436 self._psi.add_tag(tag) -> 1438 self.gate_opts = ensure_dict(gate_opts) 1439 self.gate_opts.setdefault("contract", gate_contract) 1440 self.gate_opts.setdefault("propagate_tags", gate_propagate_tags) File ~/.local/lib/python3.10/site-packages/quimb/utils.py:189, in ensure_dict(x) 187 if x is None: 188 return {} --> 189 return dict(x)
Moreover, adding a two-qubit gate leads to this error
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[14], line 25 22 c.add(gates.CNOT(0, 1)) 24 # Execute the circuit and obtain the final state ---> 25 result = c() 27 # Print the final state 28 print(result.state()) File ~/.local/lib/python3.10/site-packages/qibo/models/circuit.py:1117, in Circuit.__call__(self, initial_state, nshots) 1115 def __call__(self, initial_state=None, nshots=1000): 1116 """Equivalent to ``circuit.execute``.""" -> 1117 return self.execute(initial_state=initial_state, nshots=nshots) File ~/.local/lib/python3.10/site-packages/qibo/models/circuit.py:1113, in Circuit.execute(self, initial_state, nshots) 1109 return GlobalBackend().execute_distributed_circuit( 1110 self, initial_state, nshots 1111 ) 1112 else: -> 1113 return GlobalBackend().execute_circuit(self, initial_state, nshots) File ~/.local/lib/python3.10/site-packages/qibotn/backends/quimb.py:78, in QuimbBackend.execute_circuit(self, circuit, initial_state, nshots, return_array) 73 if self.expectation_enabled == True: 74 raise_error( 75 NotImplementedError, "QiboTN quimb backend cannot support expectation" 76 ) ---> 78 state = eval.dense_vector_tn_qu( 79 circuit.to_qasm(), initial_state, self.mps_opts, backend="numpy" 80 ) 82 if return_array: 83 return state.flatten() File ~/.local/lib/python3.10/site-packages/qibotn/eval_qu.py:39, in dense_vector_tn_qu(qasm, initial_state, mps_opts, backend) 36 initial_state = init_state_tn(nqubits, initial_state) 38 circ_cls = qtn.circuit.CircuitMPS if mps_opts else qtn.circuit.Circuit ---> 39 circ_quimb = circ_cls.from_openqasm2_str( 40 qasm, psi0=initial_state, gate_opts=mps_opts 41 ) 43 interim = circ_quimb.psi.full_simplify(seq="DRC") 44 amplitudes = interim.to_dense(backend=backend) File ~/.local/lib/python3.10/site-packages/quimb/tensor/circuit.py:1500, in Circuit.from_openqasm2_str(cls, contents, **circuit_opts) 1498 info = parse_openqasm2_str(contents) 1499 qc = cls(info["n"], **circuit_opts) -> 1500 qc.apply_gates(info["gates"]) 1501 return qc File ~/.local/lib/python3.10/site-packages/quimb/tensor/circuit.py:1624, in Circuit.apply_gates(self, gates, **gate_opts) 1622 for gate in gates: 1623 if isinstance(gate, Gate): -> 1624 self._apply_gate(gate, **gate_opts) 1625 else: 1626 self.apply_gate(*gate, **gate_opts) File ~/.local/lib/python3.10/site-packages/quimb/tensor/circuit.py:1545, in Circuit._apply_gate(self, gate, tags, **gate_opts) 1540 SPECIAL_GATES[gate.label]( 1541 self._psi, *gate.params, *gate.qubits, **opts 1542 ) 1543 else: 1544 # apply the gate to the TN! -> 1545 self._psi.gate_(gate.array, gate.qubits, tags=tags, **opts) 1547 # keep track of the gates applied 1548 self.gates.append(gate) File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:557, in TensorNetwork1DVector.gate(self, inplace, *args, **kwargs) 555 @functools.wraps(gate_TN_1D) 556 def gate(self, *args, inplace=False, **kwargs): --> 557 return gate_TN_1D(self, *args, inplace=inplace, **kwargs) File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:231, in gate_TN_1D(tn, G, where, contract, tags, propagate_tags, info, inplace, cur_orthog, **compress_opts) 229 if contract == "swap+split": 230 if ng >= 2: --> 231 return tn.gate_with_auto_swap( 232 G, 233 where, 234 cur_orthog=cur_orthog, 235 inplace=inplace, 236 **compress_opts, 237 ) 238 else: 239 contract = True File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:1880, in MatrixProductState.gate_with_auto_swap(self, G, where, inplace, cur_orthog, **compress_opts) 1878 # make sure sites are orthog center, then apply and split 1879 mps.canonize((i, i + 1), cur_orthog) -> 1880 mps.gate_split_( 1881 G, where=(i + 1, i) if need2flip else (i, i + 1), **compress_opts 1882 ) 1884 if need2swap: 1885 # move j site back to original position 1886 mps.swap_site_to( 1887 i + 1, j, cur_orthog=(i, i + 1), inplace=True, **compress_opts 1888 ) File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:1728, in MatrixProductState.gate_split(self, G, where, inplace, **compress_opts) 1726 ix_i, ix_j = map(self.site_ind, where) 1727 # note that 'reduce-split' is unecessary: tensors have ndim<=3 -> 1728 return self.gate_inds( 1729 G, (ix_i, ix_j), contract="split", inplace=inplace, **compress_opts 1730 ) File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:3848, in tensor_network_gate_inds(self, G, inds, contract, tags, info, inplace, **compress_opts) 3841 raise ValueError( 3842 "For a parametrized gate acting on more than one site " 3843 "``contract`` must be false to preserve the array shape." 3844 ) 3846 if basic: 3847 # no gate splitting involved -> 3848 _tensor_network_gate_inds_basic( 3849 tn, G, inds, ng, tags, contract, isparam, info, **compress_opts 3850 ) 3851 else: 3852 # possible splitting of gate itself involved 3853 if ng > 2: File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:3525, in _tensor_network_gate_inds_basic(tn, G, inds, ng, tags, contract, isparam, info, **compress_opts) 3520 tlGr = tensor_contract( 3521 tl.reindex(reindex_map), tr.reindex(reindex_map), TG 3522 ) 3524 # decompose back into two tensors -> 3525 tln, *maybe_svals, trn = tlGr.split( 3526 left_inds=bnds_l, 3527 right_inds=bnds_r, 3528 bond_ind=bix, 3529 get="tensors", 3530 **compress_opts, 3531 ) 3533 if contract == "reduce-split": 3534 # move physical inds on reduced tensors 3535 # (...) 3540 # ╱ ╱ ╱ ╱ 3541 # 3542 tmp_bix_l = rand_uuid() File ~/.local/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:2483, in Tensor.split(self, *args, **kwargs) 2481 @functools.wraps(tensor_split) 2482 def split(self, *args, **kwargs): -> 2483 return tensor_split(self, *args, **kwargs) TypeError: tensor_split() got an unexpected keyword argument 'cutoff_mod'
This is due to setting every possible computation setting to False. In order to use the quimb backend's dense vector function, MPS_enabled must be True since the function uses mps_opts for its calculation. I've proposed a PR to add a note for the user in the doc to let them know that this would be an invalid configuration for computation settings #57
Additionally, error handling can be introduced under quimb.py as follows:
mps_enabled_value = runcard.get("MPS_enabled") expectation_enabled_value = runcard.get("expectation_enabled") if mps_enabled_value == False and expectation_enabled_value == False: raise TypeError("Please set either MPS_enabled or expectation_enabled to True")
@NithyasriVS , error encountered by you was due to the computation setting written after set backend. There is no issue when everything is false, I have tried it for the issue mentioned by @renatomello. This was the fix I proposed for the earlier issue. I don't think this statement is true "In order to use the quimb backend's dense vector function, MPS_enabled must be True since the function uses mps_opts for its calculation."
Irrespective of the programmatical working, I feel my point about the configuration is still valid as setting all computation settings to False may not be a meaningful way to use qibotn as the user no longer knows what their output is a computation of, especially as more features/computations get added to the QuimbBackend in the future. So, it could be useful to restrict the user from wanting to use the configuration where are settings are False.
I tried to run the example inside the
doc
file of this repo and got this errorMoreover, adding a two-qubit gate leads to this error