I am working on a project to find a unitary gate that arrives at a specific density matrix at the end. The circuit construct is shown below:
dev1 = qml.device("default.mixed", wires=2)
@qml.qnode(dev1)
def circuit(params_SU):
qml.QubitDensityMatrix(identity_matrix/2, 0)
qml.QubitDensityMatrix(rho, 1)
qml.SpecialUnitary(params_SU, [0, 1])
return qml.density_matrix([0, 1])
And the cost function is:
expected_result = rho / 2 + identity_matrix / 4
def cost(params_SU):
cost_value = np.linalg.norm(partial_trace_B(circuit(params_SU)) - expected_result)
return cost_value
and
def partial_trace_B(matrix):
partial_trace_B = np.zeros([2, 2], dtype=complex)
partial_trace_B[0][0] = matrix[0][0] + matrix[1][1]
partial_trace_B[0][1] = matrix[0][2] + matrix[1][3]
partial_trace_B[1][0] = matrix[2][0] + matrix[3][1]
partial_trace_B[1][1] = matrix[2][2] + matrix[3][3]
return partial_trace_B
However, when running the optimisation:
n_steps = 1500
theta = np.random.rand(1, 15, requires_grad=True)
costs_list = []
opt = AdamOptimizer()
for i in range(1, n_steps+1):
if i%100==0: print("Running... Current step: ", i)
theta = opt.step(cost, theta)
costs_list.append(cost(theta))
I kept getting this Value Error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
TypeError: float() argument must be a string or a real number, not 'ArrayBox'
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
Cell In[6], line 8
6 for i in range(1, n_steps+1):
7 if i%100==0: print("Running... Current step: ", i)
----> 8 theta = opt.step(cost, theta)
9 costs_list.append(cost(theta))
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\optimize\gradient_descent.py:88, in GradientDescentOptimizer.step(self, objective_fn, grad_fn, *args, **kwargs)
70 def step(self, objective_fn, *args, grad_fn=None, **kwargs):
71 """Update trainable arguments with one step of the optimizer.
72
73 Args:
(...)
85 If single arg is provided, list [array] is replaced by array.
86 """
---> 88 g, _ = self.compute_grad(objective_fn, args, kwargs, grad_fn=grad_fn)
89 new_args = self.apply_grad(g, args)
91 # unwrap from list if one argument, cleaner return
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\optimize\gradient_descent.py:117, in GradientDescentOptimizer.compute_grad(objective_fn, args, kwargs, grad_fn)
99 r"""Compute gradient of the objective function at the given point and return it along with
100 the objective function forward pass (if available).
101
(...)
114 will not be evaluted and instead ``None`` will be returned.
115 """
116 g = get_gradient(objective_fn) if grad_fn is None else grad_fn
--> 117 grad = g(*args, **kwargs)
118 forward = getattr(g, "forward", None)
120 num_trainable_args = sum(getattr(arg, "requires_grad", False) for arg in args)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\_grad.py:118, in grad.__call__(self, *args, **kwargs)
115 self._forward = self._fun(*args, **kwargs)
116 return ()
--> 118 grad_value, ans = grad_fn(*args, **kwargs) # pylint: disable=not-callable
119 self._forward = ans
121 return grad_value
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\autograd\wrap_util.py:20, in unary_to_nary.<locals>.nary_operator.<locals>.nary_f(*args, **kwargs)
18 else:
19 x = tuple(args[i] for i in argnum)
---> 20 return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\_grad.py:136, in grad._grad_with_forward(fun, x)
130 @staticmethod
131 @unary_to_nary
132 def _grad_with_forward(fun, x):
133 """This function is a replica of ``autograd.grad``, with the only
134 difference being that it returns both the gradient *and* the forward pass
135 value."""
--> 136 vjp, ans = _make_vjp(fun, x)
138 if not vspace(ans).size == 1:
139 raise TypeError(
140 "Grad only applies to real scalar-output functions. "
141 "Try jacobian, elementwise_grad or holomorphic_grad."
142 )
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\autograd\core.py:10, in make_vjp(fun, x)
8 def make_vjp(fun, x):
9 start_node = VJPNode.new_root()
---> 10 end_value, end_node = trace(start_node, fun, x)
11 if end_node is None:
12 def vjp(g): return vspace(x).zeros()
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\autograd\tracer.py:10, in trace(start_node, fun, x)
8 with trace_stack.new_trace() as t:
9 start_box = new_box(x, t, start_node)
---> 10 end_box = fun(start_box)
11 if isbox(end_box) and end_box._trace == start_box._trace:
12 return end_box._value, end_box._node
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\autograd\wrap_util.py:15, in unary_to_nary.<locals>.nary_operator.<locals>.nary_f.<locals>.unary_f(x)
13 else:
14 subargs = subvals(args, zip(argnum, x))
---> 15 return fun(*subargs, **kwargs)
Cell In[5], line 4
3 def cost(params_SU):
----> 4 cost_value = np.linalg.norm(partial_trace_B(circuit(params_SU)) - expected_result)
5 return cost_value
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\qnode.py:1027, in QNode.__call__(self, *args, **kwargs)
1022 full_transform_program._set_all_argnums(
1023 self, args, kwargs, argnums
1024 ) # pylint: disable=protected-access
1026 # pylint: disable=unexpected-keyword-arg
-> 1027 res = qml.execute(
1028 (self._tape,),
1029 device=self.device,
1030 gradient_fn=self.gradient_fn,
1031 interface=self.interface,
1032 transform_program=full_transform_program,
1033 config=config,
1034 gradient_kwargs=self.gradient_kwargs,
1035 override_shots=override_shots,
1036 **self.execute_kwargs,
1037 )
1039 res = res[0]
1041 # convert result to the interface in case the qfunc has no parameters
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\interfaces\execution.py:616, in execute(tapes, device, gradient_fn, interface, transform_program, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
614 # Exiting early if we do not need to deal with an interface boundary
615 if no_interface_boundary_required:
--> 616 results = inner_execute(tapes)
617 return post_processing(results)
619 _grad_on_execution = False
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\interfaces\execution.py:249, in _make_inner_execute.<locals>.inner_execute(tapes, **_)
247 if numpy_only:
248 tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes)
--> 249 return cached_device_execution(tapes)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\interfaces\execution.py:371, in cache_execute.<locals>.wrapper(tapes, **kwargs)
366 return (res, []) if return_tuple else res
368 else:
369 # execute all unique tapes that do not exist in the cache
370 # convert to list as new device interface returns a tuple
--> 371 res = list(fn(tuple(execution_tapes.values()), **kwargs))
373 final_res = []
375 for i, tape in enumerate(tapes):
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\contextlib.py:81, in ContextDecorator.__call__.<locals>.inner(*args, **kwds)
78 @wraps(func)
79 def inner(*args, **kwds):
80 with self._recreate_cm():
---> 81 return func(*args, **kwds)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\_qubit_device.py:460, in QubitDevice.batch_execute(self, circuits)
455 for circuit in circuits:
456 # we need to reset the device here, else it will
457 # not start the next computation in the zero state
458 self.reset()
--> 460 res = self.execute(circuit)
461 results.append(res)
463 if self.tracker.active:
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\devices\default_mixed.py:685, in DefaultMixed.execute(self, circuit, **kwargs)
683 wires_list.append(m.wires)
684 self.measured_wires = qml.wires.Wires.all_wires(wires_list)
--> 685 return super().execute(circuit, **kwargs)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\_qubit_device.py:279, in QubitDevice.execute(self, circuit, **kwargs)
276 self.check_validity(circuit.operations, circuit.observables)
278 # apply all circuit operations
--> 279 self.apply(circuit.operations, rotations=self._get_diagonalizing_gates(circuit), **kwargs)
281 # generate computational basis samples
282 if self.shots is not None or circuit.is_sampled:
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\devices\default_mixed.py:699, in DefaultMixed.apply(self, operations, rotations, **kwargs)
693 raise DeviceError(
694 f"Operation {operation.name} cannot be used after other Operations have already been applied "
695 f"on a {self.short_name} device."
696 )
698 for operation in operations:
--> 699 self._apply_operation(operation)
701 # store the pre-rotated state
702 self._pre_rotated_state = self._state
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\devices\default_mixed.py:617, in DefaultMixed._apply_operation(self, operation)
614 self._debugger.snapshots[len(self._debugger.snapshots)] = density_matrix
615 return
--> 617 matrices = self._get_kraus(operation)
619 if operation in diagonal_in_z_basis:
620 self._apply_diagonal_unitary(matrices, wires)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\devices\default_mixed.py:308, in DefaultMixed._get_kraus(self, operation)
305 if isinstance(operation, Channel):
306 return operation.kraus_matrices()
--> 308 return [operation.matrix()]
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\operation.py:775, in Operator.matrix(self, wire_order)
755 def matrix(self, wire_order=None):
756 r"""Representation of the operator as a matrix in the computational basis.
757
758 If ``wire_order`` is provided, the numerical representation considers the position of the
(...)
773 tensor_like: matrix representation
774 """
--> 775 canonical_matrix = self.compute_matrix(*self.parameters, **self.hyperparameters)
777 if wire_order is None or self.wires == Wires(wire_order):
778 return canonical_matrix
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\ops\qubit\special_unitary.py:482, in SpecialUnitary.compute_matrix(theta, num_wires)
479 if interface == "jax" and qml.math.ndim(theta) > 1:
480 # jax.numpy.expm does not support broadcasting
481 return qml.math.stack([qml.math.expm(1j * _A) for _A in A])
--> 482 return qml.math.expm(1j * A)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\math\multi_dispatch.py:151, in multi_dispatch.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
148 interface = interface or get_interface(*dispatch_args)
149 kwargs["like"] = interface
--> 151 return fn(*args, **kwargs)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\pennylane\math\multi_dispatch.py:837, in expm(tensor, like)
834 return tf.linalg.expm(tensor)
835 from scipy.linalg import expm as scipy_expm
--> 837 return scipy_expm(tensor)
File c:\Users\86986\AppData\Local\Programs\Python\Python311\Lib\site-packages\scipy\linalg\_matfuncs.py:299, in expm(A)
296 return np.exp(a)
298 if not np.issubdtype(a.dtype, np.inexact):
--> 299 a = a.astype(float)
300 elif a.dtype == np.float16:
301 a = a.astype(np.float32)
ValueError: setting an array element with a sequence.
It would be very kind if someone can provide some resolutions. Thank you so much!!! I believe the bug is due to the line in the cost function
cost_value = np.linalg.norm(partial_trace_B(circuit(params_SU)) - expected_result)
But it seems completely fine with me, and I do not know how to solve it.
np
)? $\endgroup$from pennylane import numpy as np
. $\endgroup$rho
defined? It's hard to help if you don't provide an example with all the ingredients available $\endgroup$