Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions qupulse/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from qupulse.expressions import ExpressionScalar, ExpressionLike

import numpy
import sympy as sp

try:
from math import isclose
Expand Down Expand Up @@ -151,6 +152,22 @@ def to_next_multiple(sample_rate: ExpressionLike, quantum: int,
#double negative for ceil division.
return lambda duration: -(-(duration*sample_rate)//quantum) * (quantum/sample_rate)
else:
#still return 0 if duration==0
return lambda duration: ExpressionScalar(f'{quantum}/({sample_rate})*Max({min_quanta},-(-({duration})*{sample_rate}//{quantum}))*Max(0, sign({duration}))')

qI = sp.Integer(quantum)
k = qI / sample_rate # factor to go from #quanta -> duration
mqI = sp.Integer(min_quanta)

def _build_sym(d):
u = d*sample_rate/qI # "duration in quanta" (real)
ce = sp.ceiling(u) # number of quanta after rounding up

# Enforce: 0 if d <= 0; else at least mqI quanta.
# max(mqI, ceil(u)) <=> mqI if u <= mqI, else ceil(u)
# do not evaluate right now because parameters could still be variable,
# then it's just overhead.
return sp.Piecewise(
(0, sp.Le(d, 0)),
(k*mqI, sp.Le(u, mqI)),
(k*ce, True)
, evaluate=False)

return lambda duration: ExpressionScalar(_build_sym(duration))
32 changes: 17 additions & 15 deletions tests/utils/utils_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class ToNextMultipleTests(unittest.TestCase):
def test_to_next_multiple(self):
from qupulse.utils.types import TimeType
from qupulse.expressions import ExpressionScalar
precision_digits = 12

duration = TimeType.from_float(47.1415926535)
evaluated = to_next_multiple(sample_rate=TimeType.from_float(2.4),quantum=16)(duration)
Expand All @@ -120,31 +121,32 @@ def test_to_next_multiple(self):
self.assertEqual(evaluated, expected)

duration = 6185240.0000001
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=13)(duration)
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=13)(duration).evaluate_numeric()
expected = 6185248
self.assertEqual(evaluated, expected)
self.assertAlmostEqual(evaluated, expected, precision_digits)

duration = 63.99
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=4)(duration).evaluate_numeric()
expected = 64
self.assertAlmostEqual(evaluated, expected, precision_digits)

duration = 64.01
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=4)(duration).evaluate_numeric()
expected = 80
self.assertAlmostEqual(evaluated, expected, precision_digits)

duration = 0.
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=13)(duration)
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=13)(duration).evaluate_numeric()
expected = 0.
self.assertEqual(evaluated, expected)
self.assertAlmostEqual(evaluated, expected, precision_digits)

duration = ExpressionScalar('abc')
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=13)(duration).evaluate_in_scope(dict(abc=0.))
expected = 0.
self.assertEqual(evaluated, expected)
self.assertAlmostEqual(evaluated, expected, precision_digits)

duration = ExpressionScalar('q')
evaluated = to_next_multiple(sample_rate=ExpressionScalar('w'),quantum=16,min_quanta=1)(duration).evaluate_in_scope(
dict(q=3.14159,w=1.0))
expected = 16.
self.assertEqual(evaluated, expected)

#bracket silent bug
duration = ExpressionScalar('51 + q*51')
evaluated = to_next_multiple(sample_rate=1.0,quantum=16,min_quanta=1)(duration).evaluate_in_scope(
dict(q=3.14159,))
expected = 224.
self.assertEqual(evaluated, expected)


self.assertAlmostEqual(evaluated, expected, precision_digits)
Loading