Pennylane
The definitive open-source Python framework for quantum programming. Built by researchers, for research. Suitable for Quantum Machine Learning.
This framework can run on CPU and GPU using the built in devices. The following example shows the Pennylane framework with GPU device.
IMPORTANT: If you make use of GPU queues, it is mandatory to select a minimum number of CPU cores given by 16 cores/GPU multiplied by the amount of nodes selected and the number of selected GPUs (16 cores/gpu * num. GPUs * num. nodes).
Usage
Example script : testPennylaneGPU.sh
#!/bin/bash
#SBATCH -e pennylanegpu-errors%j.err
#SBATCH -o pennylanegpu-infos%j.msg
#SBATCH -p hopper # H100 queue
#SBATCH -N 2
#SBATCH --gres=gpu:1 # launch in 1-GPUs
#SBATCH --cpus-per-task=32 # 16 cores por GPU * 1 GPU * 2 nodos
module load nvidia-hpc-sdk/24.5
module load pennylane/0.33.1
nvcc --version
python test-pennylanegpu.py
Submit with :
sbatch --account=your_project_ID testPennylaneGPU.sh
Example script : test-pennylanegpu.py
#!/usr/bin/python
# General libraries
from scipy.ndimage import gaussian_filter
import warnings
# Pennylane libraries
import pennylane as qml
from pennylane import numpy as np
warnings.filterwarnings("ignore")
# Minimize the energy of this 4-qubit Hamiltonian given in Pauli operators
# H = 1.0 * XXII + 0.3 * ZIII + 1.0 * IXXI + 0.3 * IZII + 1.0 * IIXX + 0.3 * IIZI + 1.0 * XIIX + 0.3 * IIIZ
def ising_chain_ham(n, gam, pennylane = False):
# This function build the hamiltonian with Pauli operators
# n = number of spin positions
# gam = transverse field parameter
if pennylane:
import pennylane as qml
from pennylane import numpy as np
from qiskit.opflow import X, Z, I
for i in range(n):
vecX = [I] * n
vecZ = [I] * n
vecX[i] = X
vecZ[i] = Z
if i == n - 1:
vecX[0] = X
else:
vecX[i+1] = X
auxX = vecX[0]
auxZ = vecZ[0]
for a in vecX[1:n]:
auxX = auxX ^ a
for b in vecZ[1:n]:
auxZ = auxZ ^ b
if i == 0:
H = (auxX) + (gam * auxZ)
else:
H = H + (auxX) + (gam * auxZ)
if pennylane:
h_matrix = np.matrix(H.to_matrix_op().primitive.data)
return qml.pauli.pauli_decompose(h_matrix)
return H
# Hamiltonian definition
n = 4 # número de qubits
gam = 0.3
H = ising_chain_ham(n, gam, pennylane = True) # Creamos el Hamiltoniano
print("Hamiltoniano in Pauli operators:")
print("--------------------------------------------------\n")
print(H)
# choose device GPU or CPU
dev = qml.device("lightning.gpu", wires = n) # pennylane GPU simulator device
#dev = qml.device("lightning.qubit", wires = n) # pennylane CPU simulator device
init_param = (
np.array(np.random.random(n), requires_grad=True),
np.array(1.1, requires_grad=True),
np.array(np.random.random(n), requires_grad=True),
)
rot_weights = np.ones(n)
crot_weights = np.ones(n)
nums_frequency = {
"rot_param": {(0,): 1, (1,): 1, (2,): 1., (3,): 1.}, # parámetros iniciales para las rotaciones de puertas
"layer_par": {(): n},
"crot_param": {(0,): 2, (1,): 2, (2,): 2, (3,): 2},
}
@qml.qnode(dev)
def ansatz(rot_param, layer_par, crot_param, rot_weights = None, crot_weights = None):
# Ansatz
for i, par in enumerate(rot_param * rot_weights):
qml.RY(par, wires = i)
for _ in list(range(len(dev.wires))):
qml.CNOT(wires = [0, 1])
qml.CNOT(wires = [0, 2])
qml.CNOT(wires = [1, 2])
qml.CNOT(wires = [0, 3])
qml.CNOT(wires = [1, 3])
qml.CNOT(wires = [2, 3])
# Measure of expected value for hamiltonian
return qml.expval(H)
max_iterations = 500 # max. iterations for optimizer
# We use the Rotosolve optimizer built-in Pennylane
opt = qml.RotosolveOptimizer(substep_optimizer = "brute", substep_kwargs = {"num_steps": 4})
param = init_param
rot_weights = np.array([0.4, 0.8, 1.0, 1.2], requires_grad=False)
crot_weights = np.array([0.5, 1.0, 1.5, 1.8], requires_grad=False)
cost_rotosolve = []
for n in range(max_iterations):
param, cost, prev_energy = opt.step_and_cost(
ansatz,
*param,
nums_frequency=nums_frequency,
spectra = [],
full_output=True,
rot_weights=rot_weights,
crot_weights=crot_weights,
)
# Compute energy
energy = ansatz(*param, rot_weights=rot_weights, crot_weights=crot_weights)
# Calculate difference between new and old energies
conv = np.abs(energy - prev_energy)
if n % 10 == 0:
print("Iteration = {:}, Energy = {:.15f} Ha, Convergence parameter = {:.15f} Ha".format(n, energy, np.mean(conv)))
cost_rotosolve.extend(prev_energy)
print("\n==================================")
print("Number of iterations = ", max_iterations)
print("Last energy value = ", cost_rotosolve[len(cost_rotosolve) - 1])
qml.about()
More info :