Source code for psipose.ansatze.base
"""Base ansatz class for parameterized quantum circuits.
An ansatz (German for "approach" or "guess") is a parameterized quantum
circuit whose parameters are optimized during training. In variational
quantum algorithms (VQAs), the ansatz serves as the learnable component
that processes encoded data.
The choice of ansatz architecture involves trade-offs:
- Expressibility: ability to approximate arbitrary quantum states
- Trainability: avoiding barren plateaus in the optimization landscape
- Hardware efficiency: compatibility with quantum device connectivity
See Cerezo et al. (2021), "Variational Quantum Algorithms" (arXiv:2012.12265)
for a comprehensive review of ansatz design considerations.
"""
import abc
import numpy as np
[docs]
class BaseAnsatz(abc.ABC):
"""Abstract base class for quantum ansatze.
An ansatz is a parameterized quantum circuit that can be trained
by adjusting its parameters (weights). In variational quantum algorithms,
the ansatz works in concert with a feature map to learn from data.
Subclasses must implement :meth:`circuit` and :meth:`weight_shape`.
Parameters
----------
n_qubits : int
Number of qubits in the circuit.
Attributes
----------
n_qubits : int
Number of qubits.
n_params : int, optional
Total number of parameters (set by subclasses if applicable).
"""
def __init__(self, n_qubits):
self.n_qubits = n_qubits
self.n_params = None
[docs]
@abc.abstractmethod
def circuit(self, weights, wires):
"""Build the parameterized quantum circuit.
Parameters
----------
weights : array-like
Trainable parameters for the ansatz. Shape depends on the ansatz.
wires : Iterable[int]
Qubit wires to apply the circuit to.
"""
pass
[docs]
def weight_shape(self, n_qubits):
"""Return the shape of the weight array needed.
Parameters
----------
n_qubits : int
Number of qubits.
Returns
-------
tuple[int, ...] or int
Shape of the weight array. Can be a single integer (total params)
or a tuple (e.g., (n_layers, n_qubits, 3) for layered ansatze).
"""
raise NotImplementedError("Subclasses must implement weight_shape")
[docs]
def initialize_weights(self, seed=None):
"""Initialize random weights.
Parameters
----------
seed : int, optional
Random seed for reproducibility.
Returns
-------
ndarray
Randomly initialized weights with the correct shape.
"""
rng = np.random.default_rng(seed)
shape = self.weight_shape(self.n_qubits)
return rng.uniform(0, 2 * np.pi, shape)