ImportError: autoray couldn't find function 'tensordot' for backend 'quimb' when building parametrized CircuitMPS
What is your issue?
Hi, I would like to optimize gates for a circuit using CircuitMPS since I would like to use the MPS to approximate the statevector. I followed the example from https://github.com/jcmgray/quimb/blob/main/docs/tensor-circuit-mps.ipynb to build a CircuitMPS, but I opted to make the U3 parametrized so that I can optimize it. However, I get the error mentioned in the title. Perhaps, I am doing something wrong. Any help would be appreciated. Example code:
def gen_gates(N=64, x=0.1, depth=10, seed=42):
"""Generate a long range circuit that only slowly builds up entanglement.
Parameters
----------
N : int, optional
The number of qubits.
x : float, optional
The average angle magnitude of U3 rotations.
depth : int, optional
The number of fully entangling gate layers.
seed : int, optional
A random seed.
Yields
------
qtn.Gate
"""
rng = np.random.default_rng(seed)
qubits = list(range(N))
for _ in range(depth):
# random small single qubit rotations
for q in qubits:
yield qtn.Gate("U3", params=rng.normal(scale=x, size=3), qubits=[q],parametrize=True)
# random CZs between arbitrary qubit pairs
rng.shuffle(qubits)
for i in range(0, N, 2):
qa = qubits[i]
qb = qubits[i + 1]
yield qtn.Gate("CZ", params=(), qubits=[qa, qb])
circ = qtn.CircuitMPS(N=10, max_bond=200, cutoff=1e-16)
for gate in gen_gates(N=10, x=0.1, depth=10, seed=42):
if len(gate.params)==1:
circ.apply_gate(gate,contract=False)
else:
circ.apply_gate(gate)
and the error message:
KeyError Traceback (most recent call last) File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/autoray/autoray.py:548, in get_lib_fn(backend, fn) 547 try: --> 548 lib_fn = _FUNCS[backend, fn] 549 except KeyError:
KeyError: ('quimb', 'tensordot')
During handling of the above exception, another exception occurred:
AttributeError Traceback (most recent call last) File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/autoray/autoray.py:515, in import_lib_fn(backend, fn) 514 # store the function! --> 515 lib_fn = _FUNCS[backend, fn] = wrapper(getattr(lib, fn_name)) 517 except AttributeError: 518 # check if there is a backup function (e.g. for older library version)
AttributeError: module 'quimb' has no attribute 'tensordot'
During handling of the above exception, another exception occurred:
ImportError Traceback (most recent call last) Cell In[86], line 5 3 circ.apply_gate(gate,contract=False) 4 else: ----> 5 circ.apply_gate(gate)
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/circuit.py:2058, in Circuit.apply_gate(self, gate_id, params, qubits, controls, gate_round, parametrize, *gate_args, **gate_opts)
2016 """Apply a single gate to this tensor network quantum circuit. If
2017 gate_round is supplied the tensor(s) added will be tagged with
2018 'ROUND_{gate_round}'. Alternatively, putting an integer first like
(...)
2047 default gate_opts.
2048 """
2049 gate = parse_to_gate(
2050 gate_id,
2051 *gate_args,
(...)
2056 parametrize=parametrize,
2057 )
-> 2058 self._apply_gate(gate, **gate_opts)
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/circuit.py:2000, in Circuit._apply_gate(self, gate, tags, **gate_opts) 1997 G = self._backend_gate_cache[key] 1999 # apply the gate to the TN! -> 2000 self.psi.gate(G, gate.qubits, tags=tags, **opts) 2002 # keep track of the gates applied 2003 self._gates.append(gate)
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:668, in TensorNetwork1DVector.gate(self, inplace, *args, **kwargs) 666 @functools.wraps(gate_TN_1D) 667 def gate(self, *args, inplace=False, **kwargs): --> 668 return gate_TN_1D(self, *args, inplace=inplace, **kwargs)
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_1d.py:265, in gate_TN_1D(tn, G, where, contract, tags, propagate_tags, info, inplace, cur_orthog, **compress_opts) 255 return tn.gate_nonlocal( 256 G, 257 where, (...) 261 **compress_opts, 262 ) 264 # can use generic gate method --> 265 return TensorNetworkGenVector.gate( 266 tn, 267 G, 268 where, 269 contract=contract, 270 tags=tags, 271 propagate_tags=propagate_tags, 272 info=info, 273 inplace=inplace, 274 **compress_opts, 275 )
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_arbgeom.py:530, in tensor_network_ag_gate(self, G, where, contract, tags, propagate_tags, which, info, inplace, **compress_opts) 527 tags.update(old_tags) 529 # perform the actual gating --> 530 tn.gate_inds_( 531 G, inds, contract=contract, tags=tags, info=info, **compress_opts 532 ) 534 # possibly add tags based on where the gate was applied 535 if propagate_tags == "register":
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:4029, in tensor_network_gate_inds(self, G, inds, contract, tags, info, inplace, **compress_opts)
4022 raise ValueError(
4023 "For a parametrized gate acting on more than one site "
4024 "contract must be false to preserve the array shape."
4025 )
4027 if basic:
4028 # no splitting of the gate on its own involved
-> 4029 _tensor_network_gate_inds_basic(
4030 tn, G, inds, ng, tags, contract, isparam, info, **compress_opts
4031 )
4032 else:
4033 # possible splitting of gate itself involved
4034 if ng > 2:
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:3627, in _tensor_network_gate_inds_basic(tn, G, inds, ng, tags, contract, isparam, info, **compress_opts) 3625 (ix,) = inds 3626 (t,) = tn.inds_get(ix) -> 3627 t.gate(G, ix) 3628 t.add_tag(tags) 3629 return tn
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/quimb/tensor/tensor_core.py:2658, in Tensor.gate(self, G, ind, preserve_inds, transposed, inplace) 2656 new_data = do("tensordot", G, t.data, ((0,), (ax,))) 2657 else: -> 2658 new_data = do("tensordot", G, t.data, ((1,), (ax,))) 2660 if preserve_inds: 2661 # gated index is now first axis, so move it to the correct position 2662 perm = (*range(1, ax + 1), 0, *range(ax + 1, t.ndim))
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/autoray/autoray.py:80, in do(fn, like, *args, **kwargs)
31 """Do function named fn on (*args, **kwargs), peforming single
32 dispatch to retrieve fn based on whichever library defines the class of
33 the args[0], or the like keyword argument if specified.
(...)
77 <tf.Tensor: id=91, shape=(3, 3), dtype=float32>
78 """
79 backend = _choose_backend(fn, args, kwargs, like=like)
---> 80 func = get_lib_fn(backend, fn)
81 return func(*args, **kwargs)
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/autoray/autoray.py:550, in get_lib_fn(backend, fn) 548 lib_fn = _FUNCS[backend, fn] 549 except KeyError: --> 550 lib_fn = import_lib_fn(backend, fn) 551 return lib_fn
File /opt/homebrew/anaconda3/envs/qiskit/lib/python3.10/site-packages/autoray/autoray.py:523, in import_lib_fn(backend, fn) 520 if backend_alt in _MODULE_ALIASES: 521 return import_lib_fn(backend_alt, fn) --> 523 raise ImportError( 524 f"autoray couldn't find function '{fn}' for " 525 f"backend '{backend.replace('[alt]', '')}'." 526 ) 528 return lib_fn
ImportError: autoray couldn't find function 'tensordot' for backend 'quimb'.
Hi @ermalrrapaj. Yes currently parametrized gates I think are not compatible with the MPS simulator like this, since it must eagerly contract in actual data arrays.
It should be possible to run create the circuit and optimize the parameters without using parametrize=True, but it would have have to be inside the optimization loop. You would also likely have to use cutoff=0.0 for backends like jax as well.