graphix icon indicating copy to clipboard operation
graphix copied to clipboard

Fix #45: Parameterized measurement patterns

Open thierry-martinez opened this issue 1 year ago • 28 comments

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 avatar May 30 '24 09:05 thierry-martinez

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 :warning:
graphix/transpiler.py 80.95% 4 Missing :warning:
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     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar May 30 '24 09:05 codecov[bot]

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

shinich1 avatar May 31 '24 06:05 shinich1

@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.

thierry-martinez avatar May 31 '24 15:05 thierry-martinez

@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 avatar Jun 01 '24 09:06 shinich1

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 avatar Jun 01 '24 14:06 EarlMilktea

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

EarlMilktea avatar Jun 01 '24 14:06 EarlMilktea

@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.

pafloxy avatar Jun 06 '24 09:06 pafloxy

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

shinich1 avatar Jun 11 '24 17:06 shinich1

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.

thierry-martinez avatar Jun 12 '24 13:06 thierry-martinez

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 avatar Jun 20 '24 03:06 shinich1

@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.

shinich1 avatar Jun 23 '24 07:06 shinich1

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.

EarlMilktea avatar Jun 24 '24 07:06 EarlMilktea

We suggest the following:

  • implement 'placeholder' parameter implementation in graphix
  • move symbolic stuff outside, in https://github.com/TeamGraphix/graphix-symbolic/tree/master.

shinich1 avatar Jul 03 '24 16:07 shinich1

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: https://github.com/TeamGraphix/graphix-symbolic/pull/1 .

thierry-martinez avatar Jul 10 '24 08:07 thierry-martinez

@thierry-martinez There are ruff errors remain unresolved. Could you make sure that you're using the CIs correctly?

EarlMilktea avatar Jul 26 '24 18:07 EarlMilktea

Sorry, @EarlMilktea, I didn't merge this branch with master yet: it is now done and CI seems to run correctly now.

thierry-martinez avatar Jul 26 '24 21:07 thierry-martinez

@thierry-martinez CI config. is again updated. Could you update the branch?

EarlMilktea avatar Aug 02 '24 16:08 EarlMilktea

Updated! Thanks.

thierry-martinez avatar Aug 02 '24 22:08 thierry-martinez

@thierry-martinez

Checked the updates. As for the organization and quality of the code, I see (almost) no problems, but for the interface or ultimately the approach itself, I'm strongly worried about future maintainability and performance.

I suggest the following approach:

  1. Use unique identifier to distinguish different angles (not by sympy.Symbol or float)
  2. Define a class that keeps track of measurement angle/plane changes introduced on simplification
  3. In a separate package, read out the info. and perform symbolic calculus

The point is that, we only need to take into account sign flip $\alpha \to -\alpha$ and constant shift $\alpha \to \alpha + \pi$. Obviously it does not require full symbolic interfaces or ABCs, just a tiny class. With this approach, we may even rely on bindings or numba in the future.

EarlMilktea avatar Aug 03 '24 22:08 EarlMilktea

@EarlMilktea:

1. Use unique identifier to distinguish different angles (not by `sympy.Symbol` or `float`)

I think we have better to keep things generic at this level: most patterns will only have float angles, and I don't think there is a need for unique identifiers in this case. Placeholder uses object identity (is) in __eq__ and I don't think we can be more efficient than this (and it is a kind of unique identifier...). We don't use sympy anymore in this PR.

2. Define a class that keeps track of measurement angle/plane changes introduced on simplification

[...] The point is that, we only need to take into account sign flip α → − α and constant shift α → α + π .

I added support for affine expressions in 05c05a0: the code is simple to maintain and support sign flip, constant shift, and the operations performed in the transpiler.

That's enough to handle transpiling and pattern optimizations, but that's not enough for simulation.

3. In a separate package, read out the info. and perform symbolic calculus

Yes, the package graphix-symbolic uses sympy to perform symbolic simulations.

thierry-martinez avatar Aug 19 '24 23:08 thierry-martinez

Placeholder uses object identity (is) in eq and I don't think we can be more efficient than this (and it is a kind of unique identifier...).

Anyway I love this approach!

EarlMilktea avatar Aug 19 '24 23:08 EarlMilktea

@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
  • [x] 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.

bump above list posted some time ago

shinich1 avatar Aug 20 '24 13:08 shinich1

Thank you, @shinich1, for the list!

  • [x] fix visualization which seems to throw error in the presence of parameter in pattern

Fixed in 34c16ed, with a dedicated test.

  • [x] test more situations, so we can catch more errors (currently rz only with no arithmetic of param covered?)

Should have been fixed with test on random circuits (05c05a0).

  • [x] do we intend to cover simulations without subs? if so we should throw error if parameterized and being simulated?

Simulations without subs are handled with graphix-symbolic. In 3a6e38d, I added a test to check that there is an exception PlaceholderOperationError if a simulation is run on a circuit with a non-substituted Placeholder.

  • [ ] update QAOA, VQE and QNN examples.

I am not sure what to do with QAOA since there is only one pattern in qaoa.py. I added a placeholder version in VQE (with performance comparison) in 4cb326b. I added placeholders for QNN in b337abe.

  • [x] add appropriate page to docs (just autodoc, not much to write - see existing pages)

Placeholders and affine expressions are documented in 149b089.

  • [x] device interface - may need care. easy solution is to ask subs before PatternRunner initialization.

I added a test to check that there is an exception CircuitError if a PatternRunner is initialized on non-substituted parameterized patterns in 1e2f3c1.

thierry-martinez avatar Aug 20 '24 21:08 thierry-martinez

@thierry-martinez

Is it impossible to move symbolic-related ABCs/subs functions to graphix-symbolic ? Additionally, please do not define unnecessary mathematical/arithmetic abstract methods in AffineExpression, as they're not implemented or even used in graphix: consider extending it in the separate package. I understand graphix should be updated so that non-float can pass through functions, but the impact should be minimal.

EarlMilktea avatar Aug 21 '24 15:08 EarlMilktea

@EarlMilktea I believe that all the functions (subs, xreplace, and the trigonometric functions) are used in graphix. Simple and parallel substitutions apply to both Placeholder and AffineExpression. All trigonometric functions are potentially called during simulation; in these cases, AffineExpression raises an Exception, as expected, since simulation is not supported. The purpose of the parameter module is to define a common interface, which is why an abstract base class is defined.

thierry-martinez avatar Aug 23 '24 00:08 thierry-martinez

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

EarlMilktea avatar Aug 23 '24 01:08 EarlMilktea

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

thierry-martinez avatar Aug 23 '24 16:08 thierry-martinez

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 avatar Aug 23 '24 18:08 EarlMilktea

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

shinich1 avatar Jan 20 '25 11:01 shinich1

@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.

EarlMilktea avatar Jan 25 '25 14:01 EarlMilktea