Fix #48: reject non-integer measurement targets with InvalidCircuitException - #97
Open
corgab wants to merge 2 commits into
Open
Fix #48: reject non-integer measurement targets with InvalidCircuitException#97corgab wants to merge 2 commits into
corgab wants to merge 2 commits into
Conversation
Gate::measure() stored whatever array it was given, so a string or float target reached the int-typed range check as a raw TypeError, unlike every other circuit-shape mistake, and Gate::fromArray() cast such values with (int), silently turning a corrupted queued definition into a measurement of qubit 0. Both paths now validate each element and throw InvalidCircuitException::invalidMeasurementTarget() naming the offending value; explicit targets are reindexed, and an empty targets array in a serialized definition is rejected like it is in measure(). Closes #48
…e targets The (int) cast the previous commit removed for measure targets was still applied to the qubit keys of every other gate rebuilt from a serialized definition, so a corrupted payload could turn "a" into qubit 0 for h or cnot just as it could for measure. One integerIndex() helper now guards both paths through InvalidCircuitException::invalidQubitIndex(), a scalar targets value in a measure definition is rejected instead of silently meaning "measure all", and the redundant empty-targets guard is gone because measure() already owns that rule.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Gate::measure(int|array|null $targets)stored any array verbatim, someasure(['a'])passed the parameter type and failed later inCircuitBuilder::validateTargets(string $gate, int ...$qubits)as a rawTypeError, unlike every other circuit-shape mistake, which throwsInvalidCircuitException. Worse,Gate::fromArray()decoded serialized values with(int): a corrupted queued definition carryingtargets: ["a"]was silently rebuilt as a measurement of qubit 0, and the same cast turnedtarget: "a"on anhgate into qubit 0 too.Plan
Validate every qubit index once, in
Gate, for both entry points: the fluentmeasure()call and thefromArray()decoding path, for measurements and for every other gate's qubit keys.Changes
Gate::integerIndex(string $gate, mixed $value): int(private): the value must be anint, otherwiseInvalidCircuitException::invalidQubitIndex(GATE, $value).integerIndices()applies it to a list and reindexes it.Gate::measure()uses it for the array form.Gate::fromArray()uses it for every qubit key instead of(int), anddecodeMeasureTargets()returns null only for a nulltargets, rejects a scalar (previously read as "measure all") and validates the elements; the empty-array rule stays inmeasure(), which every path reaches.InvalidCircuitException::invalidQubitIndex(string $gate, mixed $value): names the gate and the offending value (Gate H expects integer qubit indices, got 'a').No config change, no new dependencies, no change for valid integer indices (a keyed
measure()array such as[2 => 1, 5 => 0]is now reindexed to[1, 0], which is what the Python side already expected; a keyed array previously serialized as a JSON object).Tests
GateTest: dataset of invalidmeasure()targets (string, numeric string, float, mixed with a valid index, nested array); explicit targets are reindexed;fromArray()dataset covering a string measure target, a scalartargets, a stringhtarget, a numeric-stringhtarget and a floatcnotcontrol, all throwing with the value in the message.CircuitBuilderTest:->measure(['a'])throwsInvalidCircuitException, not aTypeError.main(TypeError, silent qubit 0, or silent measure-all).Local: pint passed, pest 804 tests passed.
Closes #48