Hello! If applicable, put your complete code example down below. Make sure that your code:
- is 100% self-contained — someone can copy-paste exactly what is here and run it to
reproduce the behaviour you are observing - includes comments
import pennylane as qml
from pennylane import qchem
from pennylane import numpy as np
import matplotlib.pyplot as plt
#Defining an algorithm class for Grover search
#This class will have added functionality to optimize the number of calls to the oracle to experimentally verify the optimal value of sqrt(n)
class Grover:
#------------
# INITIALIZATION, Input number of qubits, shots, and the bit string to be marked for search
#------------
def __init__(self, qubits, shots, oracle_state):
#num of qubits
self.qubits = qubits
#num of shots on backend
self.shots = shots
#marked state defining the oracle - input in the form of an integer
#integer is converted to bit string which is converted to binary vector for later use in FlipState method
self.num = oracle_state
if oracle_state >= 2**self.qubits:
raise ValueError(f"Insufficient qubits. Input value less than {2**self.qubits}")
v = []
B = bin(oracle_state)[2:].zfill(self.qubits)
for i in range(len(B)):
v.append(int(B[i]))
self.oracle = v
#optimal number of oracle+diffuser cycles - this value is used as the default to reproduce the standard Grover search
self.cycles = int(np.floor(np.sqrt(self.qubits)))
#------------
# RUN METHOD, This is the core method which is used as input to all other methods
# Default run uses the optimal number of oracle cycles
# User can specify alternate number of cycles if desired
#------------
def run(self, cycles = None):
#cycles is an optional input if the user wants to implement Grover with a nonstandard number of oracle calls
if cycles is None:
cycles = self.cycles
#the run method takes in an integer to define the number of cycles - during optimization a tensor is passed to run - this converts the tensor input to one the method can use
if type(cycles) == np.tensor:
cycles = int(np.floor(cycles.item()))
#setup for Grover algorithm with initial state [1,1,...,1] (this is more optimal as the diffuser does not need to be conjugated by x gates)
initial_state = []
for i in range(self.qubits):
initial_state.append(1)
#oracle+diffusion
def OD():
#oracle
qml.FlipSign(self.oracle, wires = range(self.qubits))
#diffusion
for i in range(self.qubits):
qml.Hadamard(i)
qml.FlipSign(initial_state, wires = range(self.qubits))
for i in range(self.qubits):
qml.Hadamard(i)
#repeater oracle+diffuser
def Oracle_Diffusion(n):
for i in range(n):
OD()
#run grover
dev = qml.device("default.qubit", wires = self.qubits, shots = self.shots)
@qml.qnode(dev, interface="autograd")
def G(q):
#initial state prep
for i in range(self.qubits):
qml.PauliX(i)
qml.Hadamard(i)
#repeated component
Oracle_Diffusion(cycles)
#measurement
return qml.probs(wires = range(self.qubits))
#the output of the method is a 1D tensor of probabilities for each bit string given the number of cycles specified
return (G(cycles))
#------------
# PLOT METHOD, visualizes probabilities outputted by run method
# Default run uses the optimal number of oracle cycles
# User can specify alternate number of cycles if desired
#------------
def plot(self, cycles = None):
#same as for run
if cycles is None:
cycles = self.cycles
if type(cycles) == np.tensor:
cycles = int(np.floor(cycles.item()))
#store y values as output of run method
y = self.run(cycles)
bit_strings = [f"{x:0{self.qubits}b}" for x in range(len(y))]
plt.bar(bit_strings, y, color = "#212121")
plt.xticks(rotation="vertical")
plt.xlabel("State label")
plt.ylabel("Probability Amplitude")
plt.title("States probabilities amplitudes")
plt.show()
#------------BROKEN METHOD
# OPT METHOD, utilizes cycle input capability to experimentally recover optimal number of cycles
#------------BROKEN METHOD
def opt(self):
#initialize optimizer using integer step size as cycles must always be an integer
opt = qml.GradientDescentOptimizer(stepsize=1)
#initialize training parameter
theta = np.array(0.0, requires_grad=True)
#cost function to be trained
#sends theta -> run method and selects the amplitude of marked state from output tensor
#value is negative to permit minimization
Cost_vec = [-self.run(theta)[self.num]]
angle = [theta]
max_iterations = 100
convergence_tolerance = 1e-06
for n in range(max_iterations):
#cost function
cost = -self.run(theta)[self.num]
#BROKEN LINE - step and cost does not appear to be working with this setup
theta, prev_prob = opt.step_and_cost(cost, theta)
#store subsequent optimization steps in the corresponding vectors
Cost_vec.append(self.run(theta)[self.num])
angle.append(theta)
#convergence condition left over from VQE demo where opt code was first sourced - doesn't apply to this problem
#conv = np.abs(Prob[-1] - prev_prob)
if n % 2 == 0:
print(f"Step = {n}, probability = {Prob[-1]:.8f}")
#if conv <= convergence_tolerance:
# break
print("\n" f"Final amplitude of the target state = {Prob[-1]:.8f}")
print("\n" f"Optimal value of the circuit parameter = {angle[-1]:.4f}")
TypeError Traceback (most recent call last)
/tmp/ipykernel_70/2615489177.py in <cell line: 1>()
----> 1 G.opt()
/tmp/ipykernel_70/3335889083.py in opt(self)
89
90 cost = -self.run(theta)[self.num]
—> 91 theta, prev_prob = opt.step_and_cost(cost, theta)
92
93 Prob.append(self.run(theta)[self.num])
/opt/conda/envs/pennylane/lib/python3.9/site-packages/pennylane/optimize/gradient_descent.py in step_and_cost(self, objective_fn, grad_fn, *args, **kwargs)
57 “”"
58
—> 59 g, forward = self.compute_grad(objective_fn, args, kwargs, grad_fn=grad_fn)
60 new_args = self.apply_grad(g, args)
61
/opt/conda/envs/pennylane/lib/python3.9/site-packages/pennylane/optimize/gradient_descent.py in compute_grad(objective_fn, args, kwargs, grad_fn)
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)
119
/opt/conda/envs/pennylane/lib/python3.9/site-packages/pennylane/_grad.py in call(self, *args, **kwargs)
113 return ()
114
→ 115 grad_value, ans = grad_fn(*args, **kwargs)
116 self._forward = ans
117
/opt/conda/envs/pennylane/lib/python3.9/site-packages/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
/opt/conda/envs/pennylane/lib/python3.9/site-packages/pennylane/_grad.py in _grad_with_forward(fun, x)
131 difference being that it returns both the gradient and the forward pass
132 value.“”"
→ 133 vjp, ans = _make_vjp(fun, x)
134
135 if not vspace(ans).size == 1:
/opt/conda/envs/pennylane/lib/python3.9/site-packages/autograd/core.py 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()
/opt/conda/envs/pennylane/lib/python3.9/site-packages/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
/opt/conda/envs/pennylane/lib/python3.9/site-packages/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]
TypeError: ‘tensor’ object is not callable
And, finally, make sure to include the versions of your packages. Specifically, show us the output of qml.about()
.
Name: PennyLane
Version: 0.28.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: GitHub - PennyLaneAI/pennylane: PennyLane is a cross-platform Python library for differentiable programming of quantum computers. Train a quantum computer the same way as a neural network.
Author:
Author-email:
License: Apache License 2.0
Location: /opt/conda/envs/pennylane/lib/python3.9/site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, retworkx, scipy, semantic-version, toml
Required-by: PennyLane-Cirq, PennyLane-Lightning, PennyLane-qiskit, pennylane-qulacs, PennyLane-SF
Platform info: Linux-5.4.209-116.367.amzn2.x86_64-x86_64-with-glibc2.31
Python version: 3.9.15
Numpy version: 1.23.5
Scipy version: 1.10.0
Installed devices:
- default.gaussian (PennyLane-0.28.0)
- default.mixed (PennyLane-0.28.0)
- default.qubit (PennyLane-0.28.0)
- default.qubit.autograd (PennyLane-0.28.0)
- default.qubit.jax (PennyLane-0.28.0)
- default.qubit.tf (PennyLane-0.28.0)
- default.qubit.torch (PennyLane-0.28.0)
- default.qutrit (PennyLane-0.28.0)
- null.qubit (PennyLane-0.28.0)
- cirq.mixedsimulator (PennyLane-Cirq-0.28.0)
- cirq.pasqal (PennyLane-Cirq-0.28.0)
- cirq.qsim (PennyLane-Cirq-0.28.0)
- cirq.qsimh (PennyLane-Cirq-0.28.0)
- cirq.simulator (PennyLane-Cirq-0.28.0)
- lightning.qubit (PennyLane-Lightning-0.28.2)
- strawberryfields.fock (PennyLane-SF-0.20.1)
- strawberryfields.gaussian (PennyLane-SF-0.20.1)
- strawberryfields.gbs (PennyLane-SF-0.20.1)
- strawberryfields.remote (PennyLane-SF-0.20.1)
- strawberryfields.tf (PennyLane-SF-0.20.1)
- qiskit.aer (PennyLane-qiskit-0.28.0)
- qiskit.basicaer (PennyLane-qiskit-0.28.0)
- qiskit.ibmq (PennyLane-qiskit-0.28.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.28.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.28.0)
- qulacs.simulator (pennylane-qulacs-0.28.0)