Repository: rigetti/pyquil

Issue:
Support CHANNEL-DELAY in DefFrames
Pre-Request Checklist
---------------------

- [ ] I am running the latest versions of pyQuil and the Forest SDK
- [ ] I checked to make sure that this feature has not already been requested

Issue Description
-----------------

Translation accepts CHANNEL-DELAY attributes for frame definitions, so pyquil should support that option.


Proposed Solution
-----------------

I propose to update the DefFrame class and the corresponding parsing and stringification logic so that

- A program text that includes the new attribute within a frame definition can be parsed and the attribute will appear in the resulting DefFrame value
- A DefFrame object can be constructed to include the new attribute
- A DefFrame object that includes the new attribute will be stringified accordingly.


Additional References
---------------------

If applicable, provide some references that will help us better understand the request.


Discussion:

Patch:
diff --git a/pyquil/_parser/grammar.lark b/pyquil/_parser/grammar.lark
index 5648604..ce76e17 100644
--- a/pyquil/_parser/grammar.lark
+++ b/pyquil/_parser/grammar.lark
@@ -67,6 +67,7 @@ frame_spec : _NEWLINE_TAB frame_attr ":" ( expression | string )
             | "HARDWARE-OBJECT"
             | "CENTER-FREQUENCY"
             | "ENABLE-RAW-CAPTURE"
+            | "CHANNEL-DELAY"
 
 def_waveform : "DEFWAVEFORM" waveform_name params ":" matrix
 
diff --git a/pyquil/_parser/parser.py b/pyquil/_parser/parser.py
index e96d67d..c8c9a82 100644
--- a/pyquil/_parser/parser.py
+++ b/pyquil/_parser/parser.py
@@ -138,6 +138,7 @@ class QuilTransformer(Transformer):  # type: ignore
             "SAMPLE-RATE": "sample_rate",
             "CENTER-FREQUENCY": "center_frequency",
             "ENABLE-RAW-CAPTURE": "enable_raw_capture",
+            "CHANNEL-DELAY": "channel_delay",
         }
         options = {}
 
diff --git a/pyquil/quilbase.py b/pyquil/quilbase.py
index 68cfb54..3b80a3b 100644
--- a/pyquil/quilbase.py
+++ b/pyquil/quilbase.py
@@ -1367,6 +1367,9 @@ class DefFrame(AbstractInstruction):
     enable_raw_capture: Optional[str] = None
     """ A flag signalling that raw capture is enabled for this frame. """
 
+    channel_delay: Optional[float] = None
+    """ The amount to delay this frame, to account for hardware signal offsets [seconds]. """
+
     def out(self) -> str:
         r = f"DEFFRAME {self.frame.out()}"
         options = [
@@ -1376,6 +1379,7 @@ class DefFrame(AbstractInstruction):
             (self.hardware_object, "HARDWARE-OBJECT"),
             (self.sample_rate, "SAMPLE-RATE"),
             (self.enable_raw_capture, "ENABLE-RAW-CAPTURE"),
+            (self.channel_delay, "CHANNEL-DELAY"),
         ]
         if any(value for (value, name) in options):
             r += ":"


Test patch:
diff --git a/test/unit/test_parser.py b/test/unit/test_parser.py
index b4bf4a2..565e458 100644
--- a/test/unit/test_parser.py
+++ b/test/unit/test_parser.py
@@ -602,17 +602,25 @@ def test_parsing_defframe():
         'DEFFRAME 0 "rf":\n'
         '    SAMPLE-RATE: 2.0\n'
         '    INITIAL-FREQUENCY: 10\n'
-        '    ENABLE-RAW-CAPTURE: "true"',
+        '    ENABLE-RAW-CAPTURE: "true"\n'
+        '    CHANNEL-DELAY: 20e-9',
         DefFrame(
             Frame([Qubit(0)], "rf"),
             sample_rate=2.0,
             initial_frequency=10,
             enable_raw_capture="true",
+            channel_delay=20e-9,
         ),
     )
     assert DefFrame(
-        Frame([Qubit(0)], "rf"), enable_raw_capture="true"
-    ).out() == 'DEFFRAME 0 "rf":\n    ENABLE-RAW-CAPTURE: "true"\n'
+        Frame([Qubit(0)], "rf"),
+        enable_raw_capture="true",
+        channel_delay=12e-9,
+    ).out() == (
+        'DEFFRAME 0 "rf":\n'
+        '    ENABLE-RAW-CAPTURE: "true"\n'
+        '    CHANNEL-DELAY: 1.2e-08\n'
+    )
 
     with pytest.raises(UnexpectedToken) as excp:
         parse('DEFFRAME 0 "rf":\n' "    UNSUPPORTED: 2.0\n")