Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use quil-rs FrameSet API and compatibility layer #1543

Merged
Merged
15 changes: 9 additions & 6 deletions pyquil/quil.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,7 @@
_convert_to_py_instructions,
)
from pyquil.quiltcalibrations import (
CalibrationError,
CalibrationMatch,
expand_calibration,
match_calibration,
_convert_to_calibration_match,
)

Expand Down Expand Up @@ -130,12 +127,15 @@ def __init__(self, *instructions: InstructionDesignator):
@property
def calibrations(self) -> List[DefCalibration]:
"""A list of Quil-T calibration definitions."""
return self._program.calibrations.calibrations
return [DefCalibration._from_rs_calibration(cal) for cal in self._program.calibrations.calibrations]

@property
def measure_calibrations(self) -> List[DefMeasureCalibration]:
"""A list of measure calibrations"""
return self._program.calibrations.measure_calibrations
return [
DefMeasureCalibration._from_rs_measure_calibration_definition(cal)
for cal in self._program.calibrations.measure_calibrations
]

@property
def waveforms(self) -> Dict[str, DefWaveform]:
Expand All @@ -145,7 +145,10 @@ def waveforms(self) -> Dict[str, DefWaveform]:
@property
def frames(self) -> Dict[Frame, DefFrame]:
"""A mapping from Quil-T frames to their definitions."""
return self._program.frames.get_all_frames()
return {
Frame._from_rs_frame_identifier(frame): DefFrame._from_rs_attribute_values(frame, attributes)
for frame, attributes in self._program.frames.get_all_frames().items()
}

@property
def declarations(self) -> Dict[str, Declare]:
Expand Down
30 changes: 19 additions & 11 deletions pyquil/quilbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -1504,13 +1504,21 @@ def __new__(
attributes = {
key: DefFrame._to_attribute_value(value)
for key, value in zip(
["direction", "initial_frequency", "hardware_object", "sample_rate", "center_frequency"],
["DIRECTION", "INITIAL-FREQUENCY", "HARDWARE-OBJECT", "SAMPLE-RATE", "CENTER-FREQUENCY"],
[direction, initial_frequency, hardware_object, sample_rate, center_frequency],
)
if value is not None
}
return super().__new__(cls, frame, attributes)

@classmethod
def _from_rs_frame_definition(cls, def_frame: quil_rs.FrameDefinition) -> "DefFrame":
return super().__new__(def_frame.frame, def_frame.attributes)

@classmethod
def _from_rs_attribute_values(cls, frame: quil_rs.FrameIdentifier, attributes: Dict[str, quil_rs.AttributeValue]):
return super().__new__(cls, frame, attributes)

@staticmethod
def _to_attribute_value(value: Union[str, float]) -> quil_rs.AttributeValue:
if isinstance(value, str):
Expand Down Expand Up @@ -1546,40 +1554,40 @@ def _get_attribute(self, name: str) -> Optional[Union[str, float]]:

@property
def direction(self) -> Optional[str]:
return self._get_attribute("direction") # type: ignore
return self._get_attribute("DIRECTION") # type: ignore

@direction.setter
def direction(self, direction: str):
self._set_attribute("direction", direction)
self._set_attribute("DIRECTION", direction)

@property
def initial_frequency(self) -> Optional[float]:
return self._get_attribute("initial_frequency") # type: ignore
return self._get_attribute("INITIAL-FREQUENCY") # type: ignore

@initial_frequency.setter
def initial_frequency(self, initial_frequency: float):
self._set_attribute("initial_frequency", initial_frequency)
self._set_attribute("INITIAL-FREQUENCY", initial_frequency)

@property
def hardware_object(self) -> Optional[str]:
return self._get_attribute("hardware_object") # type: ignore
return self._get_attribute("HARDWARE-OBJECT") # type: ignore

@hardware_object.setter
def hardware_object(self, hardware_object: str):
self._set_attribute("hardware_object", hardware_object)
self._set_attribute("HARDWARE-OBJECT", hardware_object)

@property
def sample_rate(self) -> Frame:
return self._get_attribute("sample_rate") # type: ignore
return self._get_attribute("SAMPLE-RATE") # type: ignore

@sample_rate.setter
def sample_rate(self, sample_rate: float):
self._set_attribute("sample_rate", sample_rate)
self._set_attribute("SAMPLE-RATE", sample_rate)

@property
def center_frequency(self) -> Frame:
return self._get_attribute("center_frequency") # type: ignore
return self._get_attribute("CENTER-FREQUENCY") # type: ignore

@center_frequency.setter
def center_frequency(self, center_frequency: float):
self._set_attribute("center_frequency", center_frequency)
self._set_attribute("CENTER-FREQUENCY", center_frequency)
17 changes: 17 additions & 0 deletions test/unit/__snapshots__/test_quil.ambr
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# name: TestProgram.test_calibrations
list([
Calibration { instructions: [Gate(Gate { name: "X", parameters: [], qubits: [Fixed(0)], modifiers: [] })], modifiers: [], name: "Calibrate", parameters: [], qubits: [Fixed(0)] },
Calibration { instructions: [Gate(Gate { name: "Y", parameters: [], qubits: [Fixed(1)], modifiers: [] })], modifiers: [], name: "Reticulating-Splines", parameters: [Variable("Spline")], qubits: [Fixed(1)] },
])
# ---
# name: TestProgram.test_calibrations.1
list([
MeasureCalibrationDefinition { qubit: Some(Fixed(2)), parameter: "theta", instructions: [Gate(Gate { name: "Z", parameters: [], qubits: [Fixed(2)], modifiers: [] })] },
])
# ---
# name: TestProgram.test_frames
dict({
FrameIdentifier { name: "frame", qubits: [Fixed(1)] }: FrameDefinition { identifier: FrameIdentifier { name: "frame", qubits: [Fixed(1)] }, attributes: {"CENTER-FREQUENCY": Expression(Number(Complex { re: 440.0, im: 0.0 }))} },
FrameIdentifier { name: "other_frame", qubits: [Fixed(1)] }: FrameDefinition { identifier: FrameIdentifier { name: "other_frame", qubits: [Fixed(1)] }, attributes: {"CENTER-FREQUENCY": Expression(Number(Complex { re: 432.0, im: 0.0 }))} },
})
# ---
# name: test_binary_classicals
'''
AND ro[0] ro[1]
Expand Down
20 changes: 10 additions & 10 deletions test/unit/__snapshots__/test_quilbase.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
# ---
# name: TestDefFrame.test_out[With-Optionals].1
set({
'\tcenter_frequency: 440',
'\tdirection: "direction"',
'\thardware_object: "hardware_object"',
'\tinitial_frequency: 1.39',
'\tsample_rate: 44.1',
'\tCENTER-FREQUENCY: 440',
'\tDIRECTION: "direction"',
'\tHARDWARE-OBJECT: "hardware_object"',
'\tINITIAL-FREQUENCY: 1.39',
'\tSAMPLE-RATE: 44.1',
})
# ---
# name: TestDefFrame.test_str[Frame-Only]
Expand All @@ -53,11 +53,11 @@
# ---
# name: TestDefFrame.test_str[With-Optionals].1
set({
'\tcenter_frequency: 440',
'\tdirection: "direction"',
'\thardware_object: "hardware_object"',
'\tinitial_frequency: 1.39',
'\tsample_rate: 44.1',
'\tCENTER-FREQUENCY: 440',
'\tDIRECTION: "direction"',
'\tHARDWARE-OBJECT: "hardware_object"',
'\tINITIAL-FREQUENCY: 1.39',
'\tSAMPLE-RATE: 44.1',
})
# ---
# name: TestDefMeasureCalibration.test_out[MemoryReference]
Expand Down
33 changes: 32 additions & 1 deletion test/unit/test_quil.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
##############################################################################
import re
from math import pi
from typing import Dict

import numpy as np
import pytest
from syrupy.assertion import SnapshotAssertion
import qcs_sdk.quil.instructions as quil_rs

from pyquil.gates import (
Expand Down Expand Up @@ -78,14 +80,16 @@
Pragma,
validate_supported_quil,
)
from pyquil.quilatom import MemoryReference, Parameter, QubitPlaceholder, Sub, quil_cos, quil_sin
from pyquil.quilatom import Frame, MemoryReference, Parameter, QubitPlaceholder, Sub, quil_cos, quil_sin
from pyquil.quilbase import (
DefGate,
DefFrame,
Gate,
Qubit,
JumpWhen,
Declare,
DefCalibration,
DefMeasureCalibration,
ClassicalNot,
DefPermutationGate,
)
Expand Down Expand Up @@ -1306,3 +1310,30 @@ def test_params_pi_and_precedence():
prog = Program(f"RX({more_less_trivial_pi}) 0")
exp = str(prog[0].params[0])
assert _eval_as_np_pi(more_less_trivial_pi) == _eval_as_np_pi(exp)


class TestProgram:
def test_calibrations(self, snapshot: SnapshotAssertion):
program = Program(
"DEFCAL Calibrate 0:\n\tX 0",
DefCalibration("Reticulating-Splines", [Parameter("Spline")], [Qubit(1)], [Y(1)]),
DefMeasureCalibration(Qubit(2), MemoryReference("theta"), [Z(2)]),
)

calibrations = program.calibrations
measure_calibrations = program.measure_calibrations
assert all((isinstance(cal, DefCalibration) for cal in program.calibrations))
assert all((isinstance(cal, DefMeasureCalibration) for cal in program.measure_calibrations))
assert calibrations == snapshot
assert measure_calibrations == snapshot

def test_frames(self, snapshot: SnapshotAssertion):
program = Program(
'DEFFRAME 1 "frame":\n\tCENTER-FREQUENCY: 440',
DefFrame(Frame([Qubit(1)], "other_frame"), center_frequency=432.0),
)
frames = program.frames
assert all(
(isinstance(frame, Frame) and isinstance(def_frame, DefFrame) for frame, def_frame in frames.items())
)
assert frames == snapshot