def test_eval(): x = Parameter('x') assert substitute(x, {x: 5}) == 5 y = Parameter('y') assert substitute(x + y, {x: 5, y: 6}) == 11 assert substitute(x + y, {x: 5}) == 5 + y assert substitute(quil_exp(x), {y: 5}) != np.exp(5) assert substitute(quil_exp(x), {x: 5}) == np.exp(5) assert np.isclose(substitute(quil_sin(x * x**2 / y), { x: 5.0, y: 10.0 }), np.sin(12.5)) assert np.isclose(substitute(quil_sqrt(x), { x: 5.0, y: 10.0 }), np.sqrt(5.0)) assert np.isclose(substitute(quil_cis(x), { x: 5.0, y: 10.0 }), np.exp(1j * 5.0)) assert np.isclose(substitute(x - y, {x: 5.0, y: 10.0}), -5.) assert substitute(quil_cis(x), {y: 5}) == quil_cis(x) assert np.allclose(substitute_array([quil_sin(x), quil_cos(x)], {x: 5}), [np.sin(5), np.cos(5)])
def _wf_from_dict(name: str, params: Dict[str, Union[Expression, Real, Complex]]) -> TemplateWaveform: """Construct a TemplateWaveform from a name and a dictionary of properties. :param name: The Quil-T name of the template. :param params: A mapping from parameter names to their corresponding values. :returns: A template waveform. """ params = copy(params) if name not in _waveform_classes: raise ValueError(f"Unknown template waveform {name}.") cls = _waveform_classes[name] fields = getattr(cls, "__dataclass_fields__", {}) for param, value in params.items(): if param not in fields: raise ValueError(f"Unexpected parameter '{param}' in {name}.") if isinstance(value, Expression): value = substitute(value, {}) if isinstance(value, Real): # normalize to float params[param] = float(value) elif isinstance(value, Complex): # no normalization needed pass else: raise ValueError(f"Unable to resolve parameter '{param}' in template {name} to a constant value.") for field, spec in fields.items(): if field not in params and spec.default is not None: raise ValueError(f"Missing parameter '{field}' in {name}.") return cls(**params)
def test_substitute_memory_reference(): x_0 = MemoryReference("x", 0, declared_size=2) x_1 = MemoryReference("x", 1, declared_size=2) # complete substitutions assert substitute(x_0, {x_0: 5}) == 5 assert substitute(x_0 + x_1, {x_0: +5, x_1: -5}) == 0 assert substitute(x_0 - x_1, {x_0: +5, x_1: -5}) == 10 assert substitute(x_0 * x_1, {x_0: +5, x_1: -5}) == -25 assert substitute(x_0 / x_1, {x_0: +5, x_1: -5}) == -1 assert substitute(x_0 * x_0**2 / x_1, {x_0: 5, x_1: 10}) == 12.5 assert np.isclose(substitute(quil_exp(x_0), {x_0: 5, x_1: 10}), np.exp(5)) assert np.isclose(substitute(quil_sin(x_0), {x_0: 5, x_1: 10}), np.sin(5)) assert np.isclose(substitute(quil_cos(x_0), {x_0: 5, x_1: 10}), np.cos(5)) assert np.isclose(substitute(quil_sqrt(x_0), { x_0: 5, x_1: 10 }), np.sqrt(5)) assert np.isclose(substitute(quil_cis(x_0), { x_0: 5, x_1: 10 }), np.exp(1j * 5.0)) # incomplete substitutions y = MemoryReference("y", 0, declared_size=1) z = MemoryReference("z", 0, declared_size=1) assert substitute(y + z, {y: 5}) == 5 + z assert substitute(quil_cis(z), {y: 5}) == quil_cis(z) # array substitution pass-through a = MemoryReference("a", 0, declared_size=1) assert np.allclose(substitute_array([quil_sin(a), quil_cos(a)], {a: 5}), [np.sin(5), np.cos(5)])
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"], SwapPhase: ["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