Skip to content

Commit

Permalink
Use quil-rs FrameSet API and compatibility layer (#1543)
Browse files Browse the repository at this point in the history
* setup Frame and DefFrame test suites

* add eq test

* back Frame with quil_rs FrameDefinition

* back DefFrame with quil_rs.FrameDefinition

* fix flaky DefFrame snapshot tests

* cleanup imports

* "unfreeze" Frame properties

* use FrameSet API and compatibility layer, with tests

* update calibrations property as well

* center_frequency -> CENTER-FREQUENCY

* fix attribute names in DefFrame

* update snapshot
  • Loading branch information
MarquessV committed Mar 17, 2023
1 parent 961a8d2 commit 651839a
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 28 deletions.
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

0 comments on commit 651839a

Please sign in to comment.