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

Fix #45: Parameterized measurement patterns #158

Open
wants to merge 53 commits into
base: master
Choose a base branch
from

Conversation

thierry-martinez
Copy link
Contributor

This commit is yet another tentative to implement parameterized measurement patterns, to fulfill issue #45 (previous tentative: #68).

This commit adds two methods to the class Pattern:

  • is_parameterized() returns True if there is at least one measurement angle that is not just an instance of numbers.Number: indeed, a parameterized pattern is a pattern where at least one measurement angle is an expression that is not a number, typically an instance of sympy.Expr (but we don't force to choose sympy here).

  • subs(variable, substitute) returns a copy of the pattern where occurrences of the given variable in measurement angles are substituted by the given value. Substitution is performed by calling the method subs on measurement angles, if the method exists, which is the case in particular for sympy.Expr. If the substitution returns a number, this number is coerced to float, to get numbers that implement the full number protocol (in particular, sympy numbers don't implement cos).

@thierry-martinez thierry-martinez force-pushed the parameterized branch 2 times, most recently from 3093bdd to a5e16de Compare May 30, 2024 09:38
Copy link

codecov bot commented May 30, 2024

Codecov Report

Attention: Patch coverage is 81.87050% with 126 lines in your changes missing coverage. Please review.

Project coverage is 72.95%. Comparing base (ec4c582) to head (5feac05).
Report is 5 commits behind head on master.

Files Patch % Lines
graphix/parameter.py 80.54% 122 Missing ⚠️
graphix/transpiler.py 80.95% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #158      +/-   ##
==========================================
+ Coverage   71.82%   72.95%   +1.13%     
==========================================
  Files          30       31       +1     
  Lines        5359     6038     +679     
==========================================
+ Hits         3849     4405     +556     
- Misses       1510     1633     +123     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@shinich1
Copy link
Contributor

@thierry-martinez great, is the intention to merge @pafloxy's #68-equivalent code first (when it's ready), before merging this?

@thierry-martinez
Copy link
Contributor Author

@thierry-martinez great, is the intention to merge @pafloxy's #68-equivalent code first (when it's ready), before merging this?

I adapted #68 code for Parameter class in the commit 81bbeb7 I just pushed. #68 was incorrect because arithmetic operators changed parameters in place (computing alpha + 1 did change the value of alpha to alpha + 1!). In this PR, we distinguish between Parameter (alpha) and ParameterExpression (alpha + 1), and a Parameter is a particular case of ParameterExpression.

The test test_parameter_simulation is illustrative: we can either substitute a parameter by a value in a pattern then simulate, or simulate symbolically (given that the pattern is deterministic!) then substitute in the (symbolic) state vector or the density matrix, and we get the same result.

Copy link

@pafloxy pafloxy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think as for now this is all that I was looking for, If @shinich1 thinks its alright maybe we should go for the merge. :)

@shinich1
Copy link
Contributor

shinich1 commented Jun 1, 2024

@thierry-martinez @pafloxy great! give us a few days to look through. A few quick comments:

  1. is TN backend working with parameters, or should we throw error in TN backend if pattern is parametrised?
    2. could you add sympy to requirements.txt?
  2. will circuit.simulate_statevector, pattern.perform_pauli_measurements, as well as visualization tool, work with parameters?

@shinich1 shinich1 requested a review from EarlMilktea June 1, 2024 09:45
@EarlMilktea
Copy link
Contributor

Let me review it later.

Anyway, is it absolutely necessary to use sympy?
I'm concerned with...

  • performance: Personally I feel sympy is far from performant.
  • type stability: sympy has no type annotations, and it seems that not even planned.
  • developer experience: Sometimes sympy makes linter (ex. flake8, Ruff) extremely slow.

Additionally, let me point out that @masa10-f is planning to completely eliminate sympy from the source.

@EarlMilktea
Copy link
Contributor

If sympy is absolutely necessary, it's OK, but we may need to verify that we're using it wisely.

graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/sim/base_backend.py Outdated Show resolved Hide resolved
graphix/sim/density_matrix.py Outdated Show resolved Hide resolved
@pafloxy
Copy link

pafloxy commented Jun 6, 2024

@thierry-martinez @pafloxy great! give us a few days to look through. A few quick comments:

  1. is TN backend working with parameters, or should we throw error in TN backend if pattern is parametrised?
    2. could you add sympy to requirements.txt?
  2. will circuit.simulate_statevector, pattern.perform_pauli_measurements, as well as visualization tool, work with parameters?

@shinich1 @thierry-martinez
Maybe you guys figured it already but I think we need to make some small modification to the visualization.py module as well. There are some checks to determine if a measurement angle is Pauli in some of the class methods for GraphVisualizer of the form

elif (
                show_pauli_measurement
                and self.meas_angles is not None
                and (
                    2 * self.meas_angles[node] == int(2 * self.meas_angles[node])
                )  # measurement angle is integer or half-integer
            ):

where we might need to add another line or so to exclude the case where the measurement angles is an instance of Parameter/ParameterExpression.

@shinich1
Copy link
Contributor

Hi @pafloxy @thierry-martinez

I think the best way is to move parameter implementation with sympy out of main graphix repository, for example a separate repo (wrapper/module) dedicated to parameterized patterns and their executions (it seems possible, given the relatively small changes required to implement?). I am happy to initiate a creation of such repository in teamgraphix organization, if that makes sense to you? for example, that can be part of extra pip installation.

The reason mostly follows @EarlMilktea 's. Sustaining maintainability is going to help a lot in the long run for everyone contributing to this repo and will help a lot those maintaining.

  1. sympy has quite a performance issue. Looking at their github repo, it seems like a recurring issue in qiskit (which has sympy incorporated) and quite a bit of effort can be saved by deciding to move it out at this point (nb as @EarlMilktea mentioned sympy will be removed from requirements.txt when gflow is refactored for performance soon.)
  2. typing, linter compatibility, as in @EarlMilktea's comment

@thierry-martinez
Copy link
Contributor Author

I propose in my last commits a version which does not require mypy.

  • The module parameter.py implements symbolic expressions so as to support parameters, but without all the symbolic. machinery of mypy (computations with known values are done numerically, not symbolically).

  • The rest of the code does not depend on parameter.py: in particular, the code for simulators is generic. If we still need the sympy version of parameters, we can implement it separately, and simulators should work without any specific modification in the code of graphix.

  • Tests for parameters are done in a specific test_parameter.py module, and the tests include circuit simulation.

@shinich1
Copy link
Contributor

shinich1 commented Jun 20, 2024

I propose in my last commits a version which does not require mypy.

  • The module parameter.py implements symbolic expressions so as to support parameters, but without all the symbolic. machinery of mypy (computations with known values are done numerically, not symbolically).
  • The rest of the code does not depend on parameter.py: in particular, the code for simulators is generic. If we still need the sympy version of parameters, we can implement it separately, and simulators should work without any specific modification in the code of graphix.
  • Tests for parameters are done in a specific test_parameter.py module, and the tests include circuit simulation.

Thank you! I believe you mean sympy instead of mypy above? Let me take a detailed look at the code soon.

@shinich1
Copy link
Contributor

shinich1 commented Jun 23, 2024

@thierry-martinez the implementation looks good to me! we need to:

  • fix visualization which seems to throw error in the presence of parameter in pattern
  • test more situations, so we can catch more errors (currently rz only with no arithmetic of param covered?)
  • do we intend to cover simulations without subs? if so we should throw error if parameterized and being simulated?
  • update QAOA, VQE and QNN examples.
  • add appropriate page to docs (just autodoc, not much to write - see existing pages)
  • device interface - may need care. easy solution is to ask subs before PatternRunner initialization.

graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
@EarlMilktea
Copy link
Contributor

I'm a little bit concerned about...

  • complexity: Is it possible to maintain parameter.py ? It's already really huge.
  • performance: I feel that current impl. cannot be faster than sympy as it's doing almost the same things.

@shinich1
Copy link
Contributor

shinich1 commented Jul 3, 2024

We suggest the following:

@thierry-martinez
Copy link
Contributor Author

As @shinich1 suggested in the above message, this PR now only provides abstract base classes for parameters, and a minimal concrete class for placeholders (symbolic angles that can solely be substituted, and that cannot appear in computation). The sympy part is implemented as a plugin in the graphix-symbolic repo: TeamGraphix/graphix-symbolic#1 .

thierry-martinez added a commit to thierry-martinez/graphix that referenced this pull request Jul 10, 2024
graphix/parameter.py Outdated Show resolved Hide resolved
tests/test_parameter.py Outdated Show resolved Hide resolved
This commit is yet another tentative to implement parameterized
measurement patterns, to fulfill issue TeamGraphix#45 (previous tentative: TeamGraphix#68).

This commit adds two methods to the class `Pattern`:

- `is_parameterized()` returns True if there is at least one
measurement angle that is not just an instance of numbers.Number:
indeed, a parameterized pattern is a pattern where at least one
measurement angle is an expression that is not a number, typically an
instance of `sympy.Expr` (but we don't force to choose sympy here).

- `subs(variable, substitute)` returns a copy of the pattern where
occurrences of the given variable in measurement angles are
substituted by the given value.  Substitution is performed by calling
the method `subs` on measurement angles, if the method exists, which
is the case in particular for `sympy.Expr`. If the substitution
returns a number, this number is coerced to `float`, to get numbers
that implement the full number protocol (in particular, sympy numbers
don't implement `cos`).
`parameter.py` is inspired by TeamGraphix#68 but is split in Parameter and
ParameterExpression.
@EarlMilktea
Copy link
Contributor

@thierry-martinez
OK, I trust you.
Let me do final checks...

examples/MBQCvqe.py Outdated Show resolved Hide resolved
@thierry-martinez
Copy link
Contributor Author

I added missing xreplace in Circuit, Statevec and DensityMatrix, and I replace some uses of numbers.Number with typing.SupportsComplex.

@EarlMilktea
Copy link
Contributor

EarlMilktea commented Aug 23, 2024

I re-reviewed you code and felt that the whole logic of graphix (inclding simulator) is affected.
Could you request reviews from @masa10-f , as I'm not sure your idea is compatible with ZX calculus?
Additionally, please wait until his changes are merged and update your code accordingly.
Meantime, let me carefully examine your code in terms of type stability, performance, and maintainability.

@EarlMilktea EarlMilktea requested a review from masa10-f August 23, 2024 18:39
Copy link
Contributor

@EarlMilktea EarlMilktea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP: May be updated later.

graphix/instruction.py Outdated Show resolved Hide resolved
graphix/parameter.py Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/parameter.py Outdated Show resolved Hide resolved
graphix/sim/base_backend.py Show resolved Hide resolved
These abstract methods were declared in `Expression` and raised an
exception in `AffineExpression`. These methods are required for
simulation, therefore they will still be implemented in parameters
with support for symbolic computation, but we can just rely on
duck-typing there.
This flag allows the user to choose between np.complex128 or O
data-types for matrices, the former being more efficient and the
latter allowing symbolic computation.
@shinich1
Copy link
Contributor

@EarlMilktea I believe this is the direction we agreed on at the meeting in Paris. could you review this PR?

@EarlMilktea
Copy link
Contributor

@thierry-martinez (CC: @shinich1 )

I'm basically agree with your idea, but I still feel that this PR should be postponed until other TODOs are resolved, because...

  • this PR makes the Pythonic layer thicker

It would make it very difficult to improve/assess the performance of the simulator if this PR were to be merged before simulator optimization/refactoring, because simulator optimization is basically the process of reducing Pythonic tasks (ex. using numpy to delegate heavy tasks to C).

  • this PR needs to use Any

I admit this PR somehow require Any, but as Any can ruin the type checker, I would prefer resolving annotation issues (mypy errors, lacking annotations, etc.) first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants