Source code for qarp.blocks._primitives.cost_operator_block
from typing import Optional
from networkx import Graph
import qarpx as qx
from .._block import SimpleBlock
[docs]
class CostOperatorBlock(SimpleBlock):
"""QAOA cost operator for a graph-encoded cost Hamiltonian.
Edges contribute ZZ rotations; linear terms contribute Z rotations.
The symbol ``γ`` is in radians: each edge of weight ``w`` emits
``rzz(w·γ) = exp(-i (w·γ/2) Z⊗Z)`` and each linear term ``rz(c·γ)``.
"""
def __init__(
self,
n_qubits: int,
problem: Graph,
linear_terms: Optional[dict] = None,
symbol_idx: int = 0,
target_qubits=None,
use_rzz: bool = True,
name: Optional[str] = None,
):
"""Args:
n_qubits: number of graph nodes.
problem: NetworkX graph with edge weights.
linear_terms: dict of single-qubit Z coefficients.
symbol_idx: index for the symbolic parameter ``gamma_<idx>`` (ASCII so the
circuit exports as valid OpenQASM 3).
use_rzz: True → use RZZ; False → CX·Rz·CX decomposition.
target_qubits, name: see ``Block``.
"""
# A user-supplied name is honoured; the default carries the layer index.
if name is None:
name = f"Cost Op. (p={symbol_idx})"
super().__init__(n_qubits, target_qubits, name=name)
self.problem = problem
self.linear_terms = linear_terms if linear_terms is not None else {}
self.symbol_idx = symbol_idx
self.use_rzz = use_rzz
[docs]
def build_vanilla(self) -> None:
gamma_name = f"gamma_{self.symbol_idx}"
edges = list(self.problem.edges(data=True))
for from_, to_, data in edges:
coef = data.get("weight", 1)
angle = qx.Param.linear(float(coef), gamma_name) # coef·γ, radians
if self.use_rzz:
self.rzz(from_, to_, angle)
else:
self.cx(from_, to_)
self.rz(to_, angle)
self.cx(from_, to_)
for term, coeff in self.linear_terms.items():
idx = int(term[0][0])
self.rz(idx, qx.Param.linear(float(coeff), gamma_name))