Add angle() casts, bit[n] -> int[n], and an explicit cast table - #409
Add angle() casts, bit[n] -> int[n], and an explicit cast table#409TheGupta2012 wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
`angle(x)` / `angle[n](x)` from a float or an angle, and `int[n](b)` / `uint[n](b)` from a `bit[n]`, were all rejected with a generic "Invalid initialization value". Angles now carry their fixed-point width. `AngleValue` is a `float` subclass holding the width alongside the value: the float stays the unrounded angle, so a declared angle reaches a gate call unchanged, while `bits` and `resize` apply the spec's `round(value / (2*pi) * 2**n)` quantization on demand. Narrowing truncates the low-order bits, so `angle[4]` "0111" narrows to `angle[2]` "01". `int[n](b)` reads a `bit[n]` register of equal width as two's complement, so "11111111" is -1 rather than out of range. A designator-less `angle(x)` now takes its width from the assignment context, as the spec's own `angle[10] c; c = angle(a + b);` requires. Other types still require the cast width to match the declaration, because their casts must commit to a width before the assignment site. `ALLOWED_CASTS` records the supported source -> target pairs in one place, so an unsupported cast reports `Cannot cast 'angle' to 'bit'` instead of the generic message. Its rows follow the spec's allowed-casts table, with pyqasm's long-standing differences listed inline. A cast argument whose type cannot be resolved skips the check, so no program that validated before is rejected on this basis. Closes #399 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
12adee1 to
07f691a
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Closes #399
Problem
angle(x)/angle[n](x)from afloator anangle, andint[n](b)/uint[n](b)from abit[n], were all rejected with a genericInvalid initialization value for variable '...'. The spec's allowed-casts table permits all of them, and its own example narrows anangle[20]to anangle[10].Approach
Fixed-point angle representation.
AngleValue(src/pyqasm/elements.py) is afloatsubclass that carries the register width alongside the value. The float itself stays the unrounded angle, so a declared angle reaches a gate call with the value it always had;bitsandresizeapply the spec'sround(value / (2*pi) * 2**n)quantization on demand. Narrowing truncates the low-order bits, the hardware-friendly of the spec's two permitted behaviours:angle[4]holding"0111"narrows toangle[2]as"01", where rounding would give"10". This makes the spec's worked bit patterns directly assertable, and it keeps the existingVariable.angle_bit_stringfield as the single place the pattern is read from.Cast table.
ALLOWED_CASTS(src/pyqasm/maps/expressions.py) records the supportedsource -> targetpairs in one readable place, so an unsupported cast reportsCannot cast 'angle' to 'bit'instead of the generic message. Rows follow the spec's table, with pyqasm's long-standing differences listed inline rather than silently changed — this PR flips no currently-accepted cast to rejected. A cast argument whose type cannot be resolved (a binary expression, a function call) skips the check entirely, so no program that validated before is rejected on this basis.bit[n]toint[n]. Built onBitValuefrom #404. An equal-width source is read as two's complement, sobit[8] b = "11111111"; int[8](b)is-1, not an out-of-range error. A wider target has no sign bit to reinterpret and stays unsigned.Size-less
angle(...). A designator-lessangle(x)now takes its fixed-point width from the assignment context, which the spec'sangle[10] c; c = angle(a + b);requires. Other types still require the cast width to match the declaration, because their casts must commit to a width before the assignment site is reached; generalizing that rule is a separate change.Tests
tests/qasm3/test_casting.py, 22 cases:bit[n]toint[n]/uint[n]including the two's-complement and wider-target paths; the spec's worked angle bit patterns (angle[4](pi)as"1000",angle[8](7 * (pi / 8))as"01110000",angle[6](pi / 2)as"010000"); truncating narrowing; lossless widening; both of the issue's angle examples; and each unsupported cast asserting aValidationErrorthat names both types. The casts that already worked are pinned with their values.Float_testintests/qasm3/resources/variables.pyhas its previously commented-outangle[8] a = angle[8](f);restored.Float_to_Bit_test's expected message changes from the value-level wording toCannot cast 'float' to 'bit'.Full suite: 850 passed, 3 skipped.
pylint10.00/10,isort,black, andmypyclean apart from the pre-existingtabulatestub error.Notes
float(angle)is deliberately untouched. The cast table marks it No, but the spec's own angle comparison example uses it, and pyqasm accepts it today. This should be raised onopenqasm/openqasmto settle the inconsistency before anyone changes the behaviour either way. It is recorded as a deviation inALLOWED_CASTSand pinned by a test.float(duration): the issue states pyqasm rejects this and that the rejection is correct. It does not —duration v = 10ns; float[32] w = float[32](v);validates today, as dodurationcasts tobool,int,uint, andangle. Behaviour is unchanged here, but the issue's premise is wrong andALLOWED_CASTSrecords the reality.Qasm3ExprEvaluator.angle_var_in_exprleaks across statements, soangle[4] a = pi; angle[2] b = pi / 2; angle[4] c = a; angle[2] d = b;raisesAll 'Angle' variables in binary expression must have the same size. This reproduces onmain. The new tests keep one angle width per program to avoid it.qbraid,qbraid-qir) imports the changed internals, and unrolled gate-parameter output is byte-identical tomain.Stacked on #404 (
feature-385-391-bit-repr-negative-indices); rebases ontomainonce #404 merges.