-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detach prefix util function #6885
Conversation
qiskit/utils/units.py
Outdated
|
||
fixed_point_3n = int(np.floor(np.log10(value) / 3)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will emit a warning if value
is 0 or less, though we probably still want to be able to handle them so they can be used with differences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Thanks @jakelishman :)
09f579b
to
929fd49
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just comments about particular exceptions we're throwing here, rather than anything else.
|
||
from qiskit.circuit.parameterexpression import ParameterExpression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the use case for allowing ParameterExpression
here? It seems more likely that the caller would be responsible for ensuring they're passing floats, rather than us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is the best scenario, but we have one exception
delay = Parameter("delay")
qc = QuantumCircuit(1)
qc.delay(delay, 0, unit="us")
qc = transpile(qc, backend)
In this code, we parametrize the delay in units of us
. The transpiler needs to convert the SI time unit into dt
to submit this circuit to backend. First, it applies prefix, then it multiplies backend._configuration.dt
. ParameterExpression
supports simple multiplication, thus these operation should be done while the actual value is parametrized. Note that unbound parameter expression cannot be converted into float.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate logic is removed with Decimal
, but the import is still kept for type annotation.
qiskit/utils/units.py
Outdated
# to avoid round-off error of prefactor | ||
_value = Decimal.from_float(value).scaleb(prefactors[unit[0]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The decimal form doesn't really avoid any more round-off errors than just doing it in floating point, if we take care to only work with positive powers of 10. All positive powers of 10 up to 10^22 have exact representations (float(1e23)
differs from the exact value by 2^23), and since floating-point operations guarantee that the result will be the closest float to the infinite-precision answer, there's the same amount of rounding here (conversion to float at the end) as there would be if we did the previous multiply-or-divide trick to keep exact representations.
That said, I don't really mind one way or the other that much. I doubt (hope, even!) that this isn't performance-critical code (where avoiding Decimal
would be better), and as you say, we'll never really be able to entirely sensibly handle cases such as apply_prefix(1e-7, 'µs')
, since float('1e-7') < Decimal('1e-7')
, but float('1e-1') > Decimal('1e-1')
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Umm... this is good point. If we avoid Decimal
we don't need to handle exception for ParameterExpression
. I'll try multiply-or-divide trick too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That worked. 1ba3e95
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine now overall. Given that apply_prefix
is already here, there's no harm in having its counterpart. There's always more that can be done with float handling, but if this is good enough for the use-cases that you have in mind, it can go in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just a couple questions inline.
test/python/utils/test_units.py
Outdated
"""Test if same value can be obtained.""" | ||
unit = "Hz" | ||
|
||
for prefix in ["P", "T", "G", "k", "m", "u", "n", "p", "f"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about µ
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test/python/utils/test_units.py
Outdated
|
||
for prefix in ["P", "T", "G", "k", "m", "u", "n", "p", "f"]: | ||
scaled_val = apply_prefix(value, prefix + unit) | ||
test_val, _ = detach_prefix(scaled_val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we validate the returned prefix matches the input from detatch_prefix()
? For u
and µ
we can just check that they both return µ
.
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
…it-terra into feature/detach_prefix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the quick update
I also think my earlier suggestion might have messed up the docs because that note ends up between |
Yeah, Google vs Numpy. I usually use google docstring stlye, but still fine with |
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the docs are all fixed now, so this should be good.
* add detach prefix function * handling of zero, negative, out of range values * add reno * black * update implementation and add precision handling * fix round off error * parameter expression handling * fix import order * multiply-or-divide trick * update logic * Update qiskit/utils/units.py Co-authored-by: Matthew Treinish <mtreinish@kortar.org> * add unit prefix test * Update qiskit/utils/units.py Co-authored-by: Matthew Treinish <mtreinish@kortar.org> Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Summary
This is a counterpart of
apply_prefix
function. The new function returns a tuple of scaled value and prefix from a given float value. This function may be used in qiskit-experiment for unit handling (apply_prefix
is already used in some places but we don't have its counterpart).Details and comments
See unittests