Hey!
I would like to construct a cost function to minimise that looks like this
C = < z1 > + < z2 > + < z1z2 >
Where is the expectation over the Hermitian observable
zz_observable = (1/2)*np.array([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]])
-
The Hermitian observable is not supported by the qiskit.basicaer backend. Do you know what might be a good replacement? I was hoping to use the noise functionality of the qiskit simulator.
-
If inside the qnode you perform the < z1 > and < z1z2 > computations the error returned is
QuantumFunctionError: Each wire in the quantum circuit can only be measured once.
Does this mean that we can’t compute both < z1 > and < z1z2 >?
Full code + errors reproduced below.
CODE
Conversion between problem idxs (with signs) to qubits idxs (without signs)
sign = lambda x: np.sign(x)
def sign_qubit(term): # s denotes the sign and a and b refer to the idx. Minus 1 from idx to return to standard indexing
a = abs(term[0]) - 1
b = abs(term[1]) - 1
sa = sign(term[0])
sb = sign(term[1])
return sa, a, sb, b
N = 2
dev = qml.device('default.qubit', wires=N)
zz_observable = (1/2)*np.array([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]])
problem = [[2, 1]]
qubits = ['zz1', 'zz2']
QAOA phases
def mixer(beta):
for q in range(N): qml.RX(beta, wires=q)
return None
def separator(gamma, problem):
for term in problem:
sa, a, sb, b = sign_qubit(term)
qml.RZ(sa * gamma, wires=a)
qml.RZ(sb * gamma, wires=b)
## ZZ operation
qml.CNOT(wires=[a, b])
qml.RZ(sb * gamma * 2., wires=b)
qml.CNOT(wires=[a, b])
return None
@qml.qnode(dev)
def qaoa(params):
for i in range(N): qml.Hadamard(wires=i)
gamma = params[0]
beta = params[1]
separator(gamma, problem)
mixer(beta)
# Cost
single_qubit_expectations = [qml.expval.PauliZ(i) for i in range(N)]
two_qubit_expectations = [qml.expval.Hermitian(zz_observable,
wires=[abs(a)-1,abs(b)-1]) for a,b in problem]
single_qubit_expectations.extend(two_qubit_expectations)
return single_qubit_expectations
initialise the optimizer
opt = qml.GradientDescentOptimizer(stepsize=0.4)
def cost(params):
return np.sum(qaoa(params))
set the number of steps
steps = 100
set the initial parameter values
params = np.array([0.01, 0.01])
for i in range(steps):
print('here')
# update the circuit parameters
params = opt.step(cost, params)
print('here')
if (i+1) % 5 == 0:
print('Cost after step {:5d}: {: .7f}'.format(i+1, cost(params)))
print('Optimized rotation angles: {}'.format(params))
ERROR
here
QuantumFunctionError Traceback (most recent call last)
in
64 print(‘here’)
65 # update the circuit parameters
—> 66 params = opt.step(cost, params)
67 print(‘here’)
68
~/anaconda3/envs/vqa/lib/python3.6/site-packages/PennyLane-0.3.1-py3.6.egg/pennylane/optimize/gradient_descent.py in step(self, objective_fn, x, grad_fn)
61 “”"
62
—> 63 g = self.compute_grad(objective_fn, x, grad_fn=grad_fn)
64
65 x_out = self.apply_grad(g, x)
~/anaconda3/envs/vqa/lib/python3.6/site-packages/PennyLane-0.3.1-py3.6.egg/pennylane/optimize/gradient_descent.py in compute_grad(objective_fn, x, grad_fn)
85 else:
86 # default is autograd
—> 87 g = autograd.grad(objective_fn)(x) # pylint: disable=no-value-for-parameter
88 return g
89
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/wrap_util.py in 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)
21 return nary_f
22 return nary_operator
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/differential_operators.py in grad(fun, x)
22 arguments as fun
, but returns the gradient instead. The function fun
23 should be scalar-valued. The gradient has the same type as the argument."""
—> 24 vjp, ans = _make_vjp(fun, x)
25 if not vspace(ans).size == 1:
26 raise TypeError("Grad only applies to real scalar-output functions. "
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/core.py in make_vjp(fun, x)
8 def make_vjp(fun, x):
9 start_node = VJPNode.new_root(x)
—> 10 end_value, end_node = trace(start_node, fun, x)
11 if end_node is None:
12 def vjp(g): return vspace(x).zeros()
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/tracer.py 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
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/wrap_util.py in unary_f(x)
13 else:
14 subargs = subvals(args, zip(argnum, x))
—> 15 return fun(*subargs, **kwargs)
16 if isinstance(argnum, int):
17 x = args[argnum]
in cost(params)
54
55 def cost(params):
—> 56 return np.sum(qaoa(params))
57
58 # set the number of steps
~/anaconda3/envs/vqa/lib/python3.6/site-packages/PennyLane-0.3.1-py3.6.egg/pennylane/decorator.py in wrapper(*args, **kwargs)
151 def wrapper(*args, **kwargs):
152 “”“Wrapper function”""
–> 153 return qnode(*args, **kwargs)
154
155 # bind the jacobian method to the wrapped function
~/anaconda3/envs/vqa/lib/python3.6/site-packages/PennyLane-0.3.1-py3.6.egg/pennylane/qnode.py in call(self, *args, **kwargs)
455 # pylint: disable=no-member
456 args = autograd.builtins.tuple(args) # prevents autograd boxed arguments from going through to evaluate
–> 457 return self.evaluate(args, **kwargs) # args as one tuple
458
459 @ae.primitive
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/tracer.py in f_wrapped(*args, **kwargs)
42 parents = tuple(box._node for _ , box in boxed_args)
43 argnums = tuple(argnum for argnum, _ in boxed_args)
—> 44 ans = f_wrapped(*argvals, **kwargs)
45 node = node_constructor(ans, f_wrapped, argvals, kwargs, argnums, parents)
46 return new_box(ans, trace, node)
~/anaconda3/envs/vqa/lib/python3.6/site-packages/autograd-1.2-py3.6.egg/autograd/tracer.py in f_wrapped(*args, **kwargs)
46 return new_box(ans, trace, node)
47 else:
—> 48 return f_raw(*args, **kwargs)
49 f_wrapped.fun = f_raw
50 f_wrapped._is_autograd_primitive = True
~/anaconda3/envs/vqa/lib/python3.6/site-packages/PennyLane-0.3.1-py3.6.egg/pennylane/qnode.py in evaluate(self, args, **kwargs)
497 m_wires = list(w for ex in self.ev for w in ex.wires)
498 if len(m_wires) != len(set(m_wires)):
–> 499 raise QuantumFunctionError(‘Each wire in the quantum circuit can only be measured once.’)
500
501 def check_op(op):
QuantumFunctionError: Each wire in the quantum circuit can only be measured once.