Skip to content

Commit bb4cbe3

Browse files
authored
Promote floats to durations during arithmetic ops (#42)
* Promote floats to durations during arithmetic ops * Added test float + duration
1 parent 6bd9937 commit bb4cbe3

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

oqpy/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,17 @@ def __init__(self, op: ast.BinaryOperator, lhs: AstConvertible, rhs: AstConverti
241241
else:
242242
raise TypeError("Neither lhs nor rhs is an expression?")
243243

244+
# Adding floats to durations is not allowed. So we promote types as necessary.
245+
if isinstance(self.type, ast.DurationType) and self.op in [
246+
ast.BinaryOperator["+"],
247+
ast.BinaryOperator["-"],
248+
]:
249+
# Late import to avoid circular imports.
250+
from oqpy.timing import make_duration
251+
252+
self.lhs = make_duration(self.lhs)
253+
self.rhs = make_duration(self.rhs)
254+
244255
def to_ast(self, program: Program) -> ast.BinaryExpression:
245256
"""Converts the OQpy expression into an ast node."""
246257
return ast.BinaryExpression(self.op, to_ast(program, self.lhs), to_ast(program, self.rhs))

tests/test_directives.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,16 @@ def test_array_declaration():
178178
prog.set(i[1], 0) # Set with literal values
179179
idx = IntVar(name="idx", init_expression=5)
180180
val = IntVar(name="val", init_expression=10)
181+
d = DurationVar(name="d", init_expression=0)
181182
prog.set(i[idx], val)
183+
prog.set(npinit[5], d - 2e-9)
184+
prog.set(npinit[0], 2 * npinit[0] + 2e-9)
182185

183186
expected = textwrap.dedent(
184187
"""
185188
int[32] idx = 5;
186189
int[32] val = 10;
190+
duration d = 0.0ns;
187191
array[bool, 2] b = {true, false};
188192
array[int[32], 5] i = {0, 1, 2, 3, 4};
189193
array[int[55], 5] i55 = {0, 1, 2, 3, 4};
@@ -199,6 +203,8 @@ def test_array_declaration():
199203
array[duration, 11] npinit = {0.0ns, 1.0ns, 2.0ns, 4.0ns};
200204
i[1] = 0;
201205
i[idx] = val;
206+
npinit[5] = d - 2.0ns;
207+
npinit[0] = 2 * npinit[0] + 2.0ns;
202208
"""
203209
).strip()
204210

@@ -321,6 +327,9 @@ def test_binary_expressions():
321327
prog.set(b1, logical_or(b2, b3))
322328
prog.set(b1, logical_and(b2, True))
323329
prog.set(b1, logical_or(False, b3))
330+
prog.set(d, d / 5)
331+
prog.set(d, d + 5e-9)
332+
prog.set(d, 5e-9 - d)
324333
prog.set(d, d + make_duration(10e-9))
325334
prog.set(f, d / make_duration(1))
326335

@@ -359,6 +368,9 @@ def test_binary_expressions():
359368
b1 = b2 || b3;
360369
b1 = b2 && true;
361370
b1 = false || b3;
371+
d = d / 5;
372+
d = d + 5.0ns;
373+
d = 5.0ns - d;
362374
d = d + 10.0ns;
363375
f = d / 1000000000.0ns;
364376
"""
@@ -367,6 +379,39 @@ def test_binary_expressions():
367379
assert prog.to_qasm() == expected
368380

369381

382+
@pytest.mark.xfail
383+
def test_add_incomptible_type():
384+
# This test should fail since we add float to a duration and then don't type cast things
385+
# properly. This test should be fixed once we land this support.
386+
prog = oqpy.Program()
387+
port = oqpy.PortVar(name="my_port")
388+
frame = oqpy.FrameVar(name="my_frame", port=port, frequency=5e9, phase=0)
389+
delay = oqpy.DurationVar(10e-9, name="d")
390+
f = oqpy.FloatVar(5e-9, "f")
391+
392+
prog.delay(delay + f, frame)
393+
394+
# Note the automatic conversion of float to duration. Do note that OpenQASM spec does not allows
395+
# `float * duration` but does allow for `const float * duration`. So this example is not
396+
# entirely spec-compliant. Though arguably the spec should be changed.
397+
expected = textwrap.dedent(
398+
"""
399+
OPENQASM 3.0;
400+
defcalgrammar "openpulse";
401+
cal {
402+
port my_port;
403+
frame my_frame = newframe(my_port, 5000000000.0, 0);
404+
}
405+
duration d = 10.0ns;
406+
float[64] f = 5e-09;
407+
408+
delay[d + f * 1s] my_frame;
409+
"""
410+
).strip()
411+
412+
assert prog.to_qasm() == expected
413+
414+
370415
def test_measure_reset_pragma():
371416
prog = Program()
372417
q = PhysicalQubits[0]

0 commit comments

Comments
 (0)