Source code for pyquil.quiltcalibrations

from copy import copy
from dataclasses import dataclass
from typing import Union, Dict, List, Any, Optional, no_type_check

from pyquil.quilatom import (
    substitute,
    Expression,
    FormalArgument,
    Frame,
    MemoryReference,
    Parameter,
    Qubit,
    TemplateWaveform,
    WaveformReference,
)
from pyquil.quilbase import (
    AbstractInstruction,
    Capture,
    Declare,
    DelayFrames,
    DelayQubits,
    DefCalibration,
    DefMeasureCalibration,
    Fence,
    FenceAll,
    Gate,
    Measurement,
    Pragma,
    Pulse,
    RawCapture,
    ResetQubit,
    SetFrequency,
    SetPhase,
    SetScale,
    ShiftFrequency,
    ShiftPhase,
    SwapPhases,
)


[docs]class CalibrationError(Exception): pass
[docs]class CalibrationDoesntMatch(CalibrationError): pass
[docs]@dataclass class CalibrationMatch: cal: Union[DefCalibration, DefMeasureCalibration] settings: Dict[Union[FormalArgument, Parameter], Any]
[docs]@no_type_check def fill_placeholders(obj, placeholder_values: Dict[Union[FormalArgument, Parameter], Any]): """Update Parameter and FormalArgument references in objects with their corresponding definitions. It is an error if the object has a Parameter or FormalArgument reference without a corresponding definition in placeholder_values. :param obj: A Quil AST object. :param placeholder_values: A dictionary mapping placeholders to their values. :returns: The updated AST object. """ try: if obj is None or isinstance(obj, (int, float, complex, Qubit, MemoryReference)): return obj elif isinstance(obj, Expression): # defer to the usual PyQuil substitution return substitute(obj, {k: v for k, v in placeholder_values.items() if isinstance(k, Parameter)}) elif isinstance(obj, FormalArgument): return placeholder_values[obj] elif isinstance(obj, Frame): return Frame(fill_placeholders(obj.qubits, placeholder_values), obj.name) elif isinstance(obj, WaveformReference): return obj elif isinstance(obj, TemplateWaveform): return obj.__class__(**fill_placeholders(obj.__dict__, placeholder_values)) elif isinstance(obj, list): return [fill_placeholders(elt, placeholder_values) for elt in obj] elif isinstance(obj, dict): return {k: fill_placeholders(v, placeholder_values) for (k, v) in obj.items()} elif isinstance(obj, tuple): return tuple([fill_placeholders(item, placeholder_values) for item in obj]) elif isinstance(obj, Pragma) and obj.command == "LOAD-MEMORY": (source,) = obj.args arg = FormalArgument(obj.freeform_string) if arg in placeholder_values: return Pragma("LOAD-MEMORY", [source], str(placeholder_values[arg])) else: return obj else: specs = { Gate: ["params", "qubits"], Measurement: ["qubit", "classical_reg"], ResetQubit: ["qubit"], Pulse: ["frame", "waveform"], SetFrequency: ["frame", "freq"], ShiftFrequency: ["frame", "freq"], SetPhase: ["frame", "phase"], ShiftPhase: ["frame", "phase"], SwapPhases: ["frameA", "frameB"], SetScale: ["frame", "scale"], Capture: ["frame", "kernel", "memory_region"], RawCapture: ["frame", "duration", "memory_region"], DelayQubits: ["qubits", "duration"], DelayFrames: ["frames", "duration"], Fence: ["qubits"], FenceAll: [], Declare: [], Pragma: [], } if type(obj) in specs: attrs = specs[type(obj)] updated = copy(obj) for attr in attrs: setattr(updated, attr, fill_placeholders(getattr(updated, attr), placeholder_values)) return updated else: raise CalibrationError(f"Unable to fill placeholders in object {obj}.") except Exception as e: raise e
# raise ValueError(f"Unable to fill placeholders in object {obj}.")
[docs]def match_calibration( instr: AbstractInstruction, cal: Union[DefCalibration, DefMeasureCalibration] ) -> Optional[CalibrationMatch]: """Match a calibration definition to an instruction. On a successful match, return a (possibly empty) dictionary mapping calibration arguments and parameters to their values. On a failure, return None. """ settings: Dict[Any, Any] = {} @no_type_check def unpack_field(cal_field, instr_field): if isinstance(cal_field, (Parameter, FormalArgument)): if instr_field is None: raise CalibrationDoesntMatch() settings[cal_field] = instr_field elif cal_field != instr_field: raise CalibrationDoesntMatch() if isinstance(instr, Measurement) and isinstance(cal, DefMeasureCalibration): try: unpack_field(cal.qubit, instr.qubit) unpack_field(cal.memory_reference, instr.classical_reg) return CalibrationMatch(cal, settings) except CalibrationDoesntMatch: return None elif isinstance(instr, Gate) and isinstance(cal, DefCalibration): try: unpack_field(cal.name, instr.name) for cal_param, instr_param in zip(cal.parameters, instr.params): unpack_field(cal_param, instr_param) for cal_arg, instr_arg in zip(cal.qubits, instr.qubits): unpack_field(cal_arg, instr_arg) return CalibrationMatch(cal, settings) except CalibrationDoesntMatch: return None else: return None
[docs]def expand_calibration(match: CalibrationMatch) -> List[AbstractInstruction]: """ " Expand the body of a calibration from a match.""" return [fill_placeholders(instr, match.settings) for instr in match.cal.instrs]