Hi! I’m writing here because I’m having a problem with a custom gate involving 14 qubits, which I would like to apply several times (on different layers). When I try to apply it, I get an error message about allocated memory. The gate is actually very large, but I noticed that for the first layers it doesn’t cause problems. After about eight layers I get the error message instead. It therefore seems to me that the algorithm memorizes all the gate parameters every time. But I’m not interested in memorizing the entire circuit, but rather just the state vector resulting at each layer. Is my guess correct? How can I solve the problem? Do you have any further advice for me? Here’s the code and errors:
PennyLane version: 0.32.0
Python version: 3.8.8
Numpy version: 1.23.5
import pennylane as qml
import numpy as np
class QuantumDevice:
def __init__(self, n_qubits):
self.n_qubits = n_qubits
self.dev = self._initialize_device()
self.qnode = QNodeWrapper(self, self.n_qubits)
def _initialize_device(self):
return qml.device('default.qubit', wires=self.n_qubits)
def set_n_qubits(self, n_qubits):
self.n_qubits = n_qubits
self.dev = self._initialize_device()
class QNodeWrapper:
def __init__(self, device, n_qubits):
self.device = device
self.n_qubits = n_qubits
self.qnode = qml.QNode(self.adiabatic_evolution, self.device.dev)
self.T = 10
self.dt = 0.01
def evaluate(self, x, mu, sigma):
return self.qnode(x, mu, sigma)
def gate(self, δμ):
n_qubits = self.n_qubits
n_control_qubits = self.n_control_qubits
n_state_qubits = n_qubits - n_control_qubits
dt = self.dt
T = self.T
N = int(2**n_control_qubits)
M = [None]*N
for k in range(N):
matrices = [np.array([[np.exp(1j*δμ[i][k]*dt**2/T), 0 ],
[0, np.exp(-1j*δμ[i][k]*dt**2/T) ]]) for i in range(n_state_qubits) ]
M[k] = matrices[0]
for i in range(1, len(matrices)):
M[k] = np.kron(M[k], matrices[i])
# Create the block-diagonal matrix
dimension = M[0].shape[0]
D = np.zeros((N * dimension, N * dimension))
for i in range(N):
D[i * dimension:(i + 1) * dimension, i * dimension:(i + 1) * dimension] = M[i]
return D
def adiabatic_evolution(self, x, mu, sigma):
n_qubits = self.n_qubits
n_control_qubits = 7
self.n_control_qubits = n_control_qubits
n_state_qubits = n_qubits - n_control_qubits
num_layers = int(self.T/self.dt)
δμ = np.random.uniform(low= - np.sqrt(3) * sigma, high= + np.sqrt(3) * sigma, size=(n_state_qubits, 2**n_control_qubits))
for layer in range(num_layers):
print('layer = ' + str(layer))
qml.QubitUnitary(self.gate(δμ), wires=range(n_qubits))
return qml.expval((qml.PauliZ(n_qubits-1)))
quantum_device = QuantumDevice(n_qubits = 14)
mu = 0.
sigma = 0.
features = np.random.rand(2**14)
quantum_device.qnode.evaluate(features, mu, sigma)
Output:
layer = 0
layer = 1
<ipython-input-2-bc9040da9ae1>:51: ComplexWarning: Casting complex values to real discards the imaginary part
D[i * dimension:(i + 1) * dimension, i * dimension:(i + 1) * dimension] = M[i]
layer = 2
layer = 3
layer = 4
layer = 5
layer = 6
layer = 7
layer = 8
layer = 9
And, finally, the error message:
---------------------------------------------------------------------------
MemoryError Traceback (most recent call last)
<ipython-input-3-9604ab584822> in <module>
5 features = np.random.rand(2**14)
6
----> 7 quantum_device.qnode.evaluate(features, mu, sigma)
<ipython-input-2-bc9040da9ae1> in evaluate(self, x, mu, sigma)
22
23 def evaluate(self, x, mu, sigma):
---> 24 return self.qnode(x, mu, sigma)
25
26 def gate(self, δμ, layer):
c:\ProgramData\Anaconda3\lib\site-packages\pennylane\qnode.py in __call__(self, *args, **kwargs)
972
973 # construct the tape
--> 974 self.construct(args, kwargs)
975
976 cache = self.execute_kwargs.get("cache", False)
c:\ProgramData\Anaconda3\lib\site-packages\pennylane\qnode.py in construct(self, args, kwargs)
870 self.interface = qml.math.get_interface(*args, *list(kwargs.values()))
871
--> 872 self._tape = make_qscript(self.func, shots)(*args, **kwargs)
873 self._qfunc_output = self.tape._qfunc_output
874
c:\ProgramData\Anaconda3\lib\site-packages\pennylane\tape\qscript.py in wrapper(*args, **kwargs)
1529 def wrapper(*args, **kwargs):
1530 with AnnotatedQueue() as q:
-> 1531 result = fn(*args, **kwargs)
1532
1533 qscript = QuantumScript.from_queue(q, shots)
<ipython-input-2-bc9040da9ae1> in adiabatic_evolution(self, x, mu, sigma)
68 for layer in range(num_layers):
69 print('layer = ' + str(layer))
---> 70 qml.QubitUnitary(self.gate(δμ, layer), wires=range(n_qubits))
71
72 return qml.expval((qml.PauliZ(n_qubits-1)))
<ipython-input-2-bc9040da9ae1> in gate(self, δμ, layer)
46 # Create the block-diagonal matrix
47 dimension = M[0].shape[0]
---> 48 D = np.zeros((N * dimension, N * dimension))
49
50 for i in range(N):
MemoryError: Unable to allocate 2.00 GiB for an array with shape (16384, 16384) and data type float64