Skip to content
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

Add helper to detect nested control-flow writes to variables #10975

Closed
wants to merge 5 commits into from

Conversation

jakelishman
Copy link
Member

Summary

This helper function is intended for use during the DAGCircuit
construction in the near term, where it will need to distinguish whether
a control-flow operation reads or writes a variable.

This is not an efficient operation on the QuantumCircuit tree
representation, and in general is something that should instead be
calculated by data-flow analysis (or similar) on a graph-based
representation of the program, or cached. However, DAGCircuit
currently does not represent control-flow well enough to do anything
like this across the circuit, so the helper method is necessary in the
short term, despite the effective quadratic complexity on the
control-flow depth of a circuit during complete recursive conversion of
blocks to DAGCircuits.

Details and comments

Depends on #10974

Close #10940.

It might be preferable to store the number of writes to variables within QuantumCircuit, but the only way to reliably keep this number up-to-date is to add an extra check within QuantumCircuit._append, and I'm wary of affecting the performance of that inner-loop function for a feature that most circuits will not use. DAGCircuit is already very inefficient with regards to classical handling at the moment and needs a more complete rework, so this feels like a reasonable compromise; performance is poorer than it could be for control-flow ops in DAGCircuit (it's already poor), but circuits that don't use it aren't affected.

This adds the representation of `expr.Var` nodes that own their own
storage locations, and consequently are not backed by existing Qiskit
objects (`Clbit` or `ClassicalRegister`).  This is the base of the
ability for Qiskit to represent manual classical-value storage in
`QuantumCircuit`, and the base for how manual storage will be
implemented.
This does not yet add the implementation of `QuantumCircuit.store`,
which will come later as part of expanding the full API of
`QuantumCircuit` to be able to support these runtime variables.

The `is_lvalue` helper is added generally to the `classical.expr` module
because it's generally useful, while `types.cast_kind` is moved from
being a private method in `expr` to a public-API function so `Store` can
use it.  These now come with associated unit tests.
This adds all the new `QuantumCircuit` methods discussed in the
variable-declaration RFC[^1], and threads the support for them through
the methods that are called in turn, such as `QuantumCircuit.append`.
It does yet not add support to methods such as `copy` or `compose`,
which will be done in a follow-up.

The APIs discussed in the RFC necessitated making `Var` nodes hashable.
This is done in this commit, as it is logically connected.  These nodes
now have enforced immutability, which is technically a minor breaking
change, but in practice required for the properties of such expressions
to be tracked correctly through circuits.

A helper attribute `Var.standalone` is added to unify the handling of
whether a variable is an old-style existing-memory wrapper, or a new
"proper" variable with its own memory.

[^1]: Qiskit/RFCs#50
This adds an inner check to the control-flow operations that their
blocks do not contain input variables, and to `QuantumCircuit.append`
that any captures within blocks are validate (in the sense of the
variables existing in the outer circuit).

In order to avoid an `import` on every call to `QuantumCircuit.append`
(especially since we're already eating the cost of an extra
`isinstance` check), this reorganises the import structure of
`qiskit.circuit.controlflow` to sit strictly _before_
`qiskit.circuit.quantumcircuit` in the import tree.  Since those are key
parts of the circuit data structure, that does make sense, although by
their nature the structures are of course recursive at runtime.
This helper function is intended for use during the `DAGCircuit`
construction in the near term, where it will need to distinguish whether
a control-flow operation reads or writes a variable.

This is not an efficient operation on the `QuantumCircuit` tree
representation, and in general is something that should instead be
calculated by data-flow analysis (or similar) on a graph-based
representation of the program, or cached.  However, `DAGCircuit`
currently does not represent control-flow well enough to do anything
like this across the circuit, so the helper method is necessary in the
short term, despite the effective quadratic complexity on the
control-flow depth of a circuit during complete recursive conversion of
blocks to `DAGCircuit`s.
@jakelishman jakelishman added the Changelog: New Feature Include in the "Added" section of the changelog label Oct 4, 2023
@jakelishman jakelishman added this to the 0.45.0 milestone Oct 4, 2023
@jakelishman jakelishman requested a review from a team as a code owner October 4, 2023 17:56
@qiskit-bot
Copy link
Collaborator

One or more of the the following people are requested to review this:

  • @Qiskit/terra-core

@coveralls
Copy link

Pull Request Test Coverage Report for Build 6409702336

  • 273 of 297 (91.92%) changed or added relevant lines in 18 files are covered.
  • 16 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.01%) to 87.026%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/circuit/classical/types/ordering.py 18 19 94.74%
qiskit/circuit/controlflow/_builder_utils.py 3 4 75.0%
qiskit/circuit/controlflow/builder.py 0 1 0.0%
qiskit/circuit/controlflow/for_loop.py 5 6 83.33%
qiskit/circuit/controlflow/if_else.py 5 6 83.33%
qiskit/circuit/controlflow/switch_case.py 4 5 80.0%
qiskit/circuit/controlflow/while_loop.py 4 5 80.0%
qiskit/circuit/classical/expr/constructors.py 5 7 71.43%
qiskit/circuit/store.py 33 35 94.29%
qiskit/circuit/controlflow/control_flow.py 35 38 92.11%
Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 4 91.67%
crates/qasm2/src/parse.rs 12 96.67%
Totals Coverage Status
Change from base Build 6407307416: 0.01%
Covered Lines: 74373
Relevant Lines: 85461

💛 - Coveralls

@jakelishman jakelishman modified the milestones: 0.45.0, 1.0.0 Oct 5, 2023
@jakelishman
Copy link
Member Author

This will be rewritten in other forms. Closing.

@jakelishman jakelishman deleted the var/cf-helpers branch December 12, 2023 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add helper methods to ControlFlowOp for managing variables in scope
3 participants