"""Hardware-efficient ansatz with single-qubit rotations and entangling gates."""
import numpy as np
import pennylane as qml
from .base import BaseAnsatz
[docs]
class HardwareEfficientAnsatz(BaseAnsatz):
"""Hardware-efficient ansatz with alternating rotations and entangling layers.
Implements the hardware-efficient ansatz from Kandala et al.,
"Hardware-efficient variational quantum eigensolver for small molecules
and quantum magnets" (Nature 549, 242-246, 2017).
Each layer consists of:
1. Single-qubit rotations (RX, RY, RZ) on each qubit
2. Entangling gates (CNOTs) in a nearest-neighbor chain
Parameters
----------
n_qubits : int
Number of qubits.
layers : int, default=2
Number of repeating layers.
Examples
--------
>>> ansatz = HardwareEfficientAnsatz(n_qubits=4, layers=3)
>>> weight_shape = ansatz.weight_shape(4) # (layers, n_qubits, 3)
"""
def __init__(self, n_qubits, layers=2):
super().__init__(n_qubits)
self.layers = layers
self.n_params = layers * n_qubits * 3
[docs]
def circuit(self, weights, wires):
"""Build the quantum circuit.
Parameters
----------
weights : array-like, shape (layers, n_qubits, 3)
Rotation parameters. weights[l, q, 0] gives RX angle,
weights[l, q, 1] gives RY angle, weights[l, q, 2] gives RZ angle
for qubit q in layer l.
wires : Iterable[int]
Qubit wires.
Notes
-----
Weights can also be a 1D array of length layers * n_qubits * 3,
which will be reshaped automatically.
"""
wires = list(wires)
n_qubits = len(wires)
if isinstance(weights, np.ndarray) and weights.ndim == 1:
weights = weights.reshape(self.layers, n_qubits, 3)
for layer in range(self.layers):
for q in range(n_qubits):
qml.RX(weights[layer, q, 0], wires=wires[q])
qml.RY(weights[layer, q, 1], wires=wires[q])
qml.RZ(weights[layer, q, 2], wires=wires[q])
if n_qubits > 1:
for q in range(n_qubits - 1):
qml.CNOT(wires=[wires[q], wires[q + 1]])
if n_qubits > 2:
qml.CNOT(wires=[wires[-1], wires[0]])
[docs]
def weight_shape(self, n_qubits):
"""Return the shape of the weight array: (layers, n_qubits, 3).
The 3 corresponds to RX, RY, RZ rotation angles per qubit
per layer, following Kandala et al. (Nature 2017).
"""
return (self.layers, n_qubits, 3)