diff --git a/qupulse/utils/__init__.py b/qupulse/utils/__init__.py index 3ad983cc..fa571537 100644 --- a/qupulse/utils/__init__.py +++ b/qupulse/utils/__init__.py @@ -131,7 +131,7 @@ def forced_hash(obj) -> int: def to_next_multiple(sample_rate: ExpressionLike, quantum: int, - min_quanta: Optional[int] = None) -> Callable[[ExpressionLike],ExpressionScalar]: + min_quanta: Optional[int] = None) -> Callable[[ExpressionScalar], ExpressionLike]: """Construct a helper function to expand a duration to one corresponding to valid sample multiples according to the arguments given. Useful e.g. for PulseTemplate.pad_to's 'to_new_duration'-argument. @@ -141,33 +141,34 @@ def to_next_multiple(sample_rate: ExpressionLike, quantum: int, quantum: number of samples to whose next integer multiple the duration shall be rounded up to. min_quanta: number of multiples of quantum not to fall short of. Returns: - A function that takes a duration (ExpressionLike) as input, and returns + A function that takes a duration as input, and returns a duration rounded up to the next valid samples count in given sample rate. The function returns 0 if duration==0, <0 is not checked if min_quanta is None. """ sample_rate = ExpressionScalar(sample_rate) + #is it more efficient to omit the Max call if not necessary? if min_quanta is None: #double negative for ceil division. return lambda duration: -(-(duration*sample_rate)//quantum) * (quantum/sample_rate) else: - 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)) \ No newline at end of file + # work with sympy + sample_rate = sample_rate.sympified_expression + duration_per_quantum = sp.Integer(quantum) / sample_rate + minimal_duration = duration_per_quantum * min_quanta + + def build_next_multiple(duration: ExpressionScalar) -> ExpressionLike: + duration = sp.sympify(duration) + n_quanta = sp.ceiling(duration / duration_per_quantum) + rounded_up_duration = n_quanta * duration_per_quantum + + next_multiple_sp = sp.Piecewise( + (0, sp.Le(n_quanta, 0)), + (minimal_duration, sp.Le(n_quanta, min_quanta)), + (rounded_up_duration, True), + evaluate=False, + ) + return ExpressionScalar(next_multiple_sp) + + return build_next_multiple