- Notifications
You must be signed in to change notification settings - Fork193
An extended RZZ pass for unbounded parameters#2072
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
yaelbh commentedDec 5, 2024
All the bugs have been fixed, it's not in draft mode anymore but ready for review. |
yaelbh commentedDec 6, 2024
Is there a risk that the pass will run again and again, forever? |
wshanks left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is very clever, Yael and Liran.
I think the concern about running forever is coming from the use of themodified variable in a loop? That variable is just used to determine whether to reuse the original data or new data and not to restart the loop, so I think it is okay.
I have a couple concerns about this PR, but they may not be issues:
Should we be concerned about the blowing up in size of the input circuit?
The simple circuit with a single rzz with angle
pgoes from having a data attribute like:[CircuitInstruction(operation=Instruction(name='rzz', num_qubits=2, num_clbits=0, params=[Parameter(p)]), qubits=(Qubit(QuantumRegister(2, 'q'), 0), Qubit(QuantumRegister(2, 'q'), 1)), clbits=())]To one like:
Details
[CircuitInstruction(operation=Instruction(name='global_phase', num_qubits=0, num_clbits=0, params=[ParameterExpression(1.5707963267949*(1 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5)))*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2 + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2 + 1.5707963267949*(sign(-p + 12.5663706143592*floor(0.0795774715459477*p) + 9.42477796076938) + 1)*((sign(p - 12.5663706143592*floor(0.0795774715459477*p) - 3.14159265358979) + 1)*sign(p - 12.5663706143592*floor(0.0795774715459477*p) - 3.14159265358979)**2/2 - sign(p - 12.5663706143592*floor(0.0795774715459477*p) - 3.14159265358979)**2 + 1)*sign(-p + 12.5663706143592*floor(0.0795774715459477*p) + 9.42477796076938)**2 - 0.785398163397448*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 - 0.785398163397448*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2)]), qubits=(), clbits=()), CircuitInstruction(operation=Instruction(name='rz', num_qubits=1, num_clbits=0, params=[ParameterExpression(1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2)]), qubits=(Qubit(QuantumRegister(2, 'q'), 0),), clbits=()), CircuitInstruction(operation=Instruction(name='rx', num_qubits=1, num_clbits=0, params=[ParameterExpression(1.5707963267949*(1 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5)))*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2 + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2 + 1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2)]), qubits=(Qubit(QuantumRegister(2, 'q'), 0),), clbits=()), CircuitInstruction(operation=Instruction(name='rz', num_qubits=1, num_clbits=0, params=[ParameterExpression(1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2)]), qubits=(Qubit(QuantumRegister(2, 'q'), 1),), clbits=()), CircuitInstruction(operation=Instruction(name='rzz', num_qubits=2, num_clbits=0, params=[ParameterExpression(-(1 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5)))*(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2 + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2/2 + (p - 6.28318530717959*floor(0.159154943091895*p + 0.5))*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5)) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2/2 + (sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 + (sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2/2)]), qubits=(Qubit(QuantumRegister(2, 'q'), 0), Qubit(QuantumRegister(2, 'q'), 1)), clbits=()), CircuitInstruction(operation=Instruction(name='rx', num_qubits=1, num_clbits=0, params=[ParameterExpression(1.5707963267949*(1 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5)))*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) + 1.5707963267949)**2 + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5))**2 + 1.5707963267949*(sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979) + 1)*((sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949) + 1)*sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2/2 - sign(p - 6.28318530717959*floor(0.159154943091895*p + 0.5) - 1.5707963267949)**2 + 1)*sign(-p + 6.28318530717959*floor(0.159154943091895*p + 0.5) + 3.14159265358979)**2)]), qubits=(Qubit(QuantumRegister(2, 'q'), 0),), clbits=())]Perhaps in the weighing of pros and cons, this large expression is better than not being able to use parametrized circuits with rzz or needing to wrap parameter values in some external method.
Do we need to be careful about adding a link between the rzz gate and the rx gate? In practice, they were added at the same time and so rx is always present when rzz is. The first version of the pass just added an assumption of there being an
XGatethough, notRXGate. Perhaps it is fine the way it is. Or should there be a check that the backend supportsRXGateas well to be safe?I wonder if the parameterized and numerical code paths should be more aligned? Perhaps not, things are readable the way they are. The parameterized path uses a single function adding on parts as it goes while the numerical one has four separate functions. The parameterized version doesn't have the option of splitting up like the numerical one does.
One minor thing -- this is not related to this PR, but while looking at it I noticed the circuit drawings in the quad method docstrings are not aligned properly. Perhaps that could be incidentally fixed here as well.
yaelbh commentedDec 8, 2024
For (2), I expect other translation passes to translate For (1), I'm more concerned than you, to the point that I estimate that this will PR eventually will not be able to merge, because of the circuit size. This is certainly something that must be checked. |
yaelbh commentedDec 8, 2024
So the pass managers are just lists of passes that get to run sequentially, not involving loops and fixed points. I suggest at minimum to check if |
| """ | ||
| def__init__(self,target:Optional[Union[Target,list[str]]]=None): | ||
| def__init__(self,target:Optional[Union[Target,List[str]]]=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
If you prefer, you can usefrom __future__ import annotations at the top of the import statements and then the new style will work for type hints. Doing this causes the type hints to be converted into strings instead of being evaluated as objects (so it doesn't make thelist[...] syntax actually work on Python 3.9; if you try to use it outside of an annotation, there will be an error).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I don't mind, do you have a preference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We are inconsistent enough in this repo that I don't think it matters much in individual PRs like this, it would be more effective to have a PR that unifies across the repo and then we start being strict. My preference is to eventually settle on thenew-style, in which case this would beTarget | list[str] | None.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I don't have a strong preference though I do think it is nice to avoid the typing imports when possible. I mainly wanted to point the option out since I saw the commit message "old style typing required by CI".
ihincks commentedDec 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Thanks for writing this example out explicitly,@wshanks . I don't have any feedback at the moment, just a question and some comments. First of all, I haven't yet looked at the implementation or any math notes, but based on the gates in the printout, I assume this is implementing something the following case logic (?):
If so, I guess it's not surprising that implementing case logic with parameter expressions end up rather complicated. If there were many thousands of these inside of an input, it would cause bottlenecks various places in the stack. To me, one of the main sticking points is where and how the user opts-in to the two extra rx gates. |
yaelbh commentedDec 10, 2024
The logic is described in a clear manner at the doc strings of the methods |
wshanks commentedJan 13, 2025
One thing I wonder about regarding the size of the expressions -- perhaps we could get Also, I agree with Ian on the point about opting into this pass. I think currently (only handling numerical RZZ parameters) it is always run. For numerical RZZ parameters, that makes sense -- if you use only angles between 0 and pi/2, it does nothing. For the parameter case, it always adds the RX gates and the user might not want that if they are already keeping their angles between 0 and pi/2. |
yaelbh commentedJan 13, 2025
Stefan Wörner proposes something along the lines of: This approach looks correct, and is expected to reduce the size of the final expressions. |
wshanks commentedJan 13, 2025
We want to make sure to take |
yaelbh commentedJan 13, 2025
In the code we should define a function that returns a general expression for an if-else condition, based on Then call that if-else function with what we need for |
yaelbh commentedJan 14, 2025
Expressions of the form don't take into account that the sign can be 0 (equality). Handling sign=0 makes quadratics unavoidable. By quadratic I refer to These quadratics greatly increase the size of the final expressions. |
yaelbh commentedJan 16, 2025
We can avoid the quadratics by adding/subtracting 0.1 (any number between 0 and 1 will do) and apply sign again: |
wshanks commentedJan 17, 2025
One option we might consider if it seems like the parametric option has too much overhead is adding a pub->pub helper function that inserts the extra gates into the circuit along with inserting the corresponding parameter values into the output pub. The parametric rzz validation error message could suggest this function when it finds a value out of range. |
ihincks commentedJan 19, 2025
@wshanks That seems like a decent interim solution. It would break the flow a bit of create->transpile->execute, but I think it would be a net win over instantiating and then sending the large parameter expressions over the wire. |
yaelbh commentedJan 20, 2025
I agree about the helper function, perhaps we will have to write an additional function to translate back parameter values to values of the original parameters. I'm still curious to give here one more try to substantially reduce the expression size, based on ideas that were raised above:
All this is valid if we are allowed to use Finally, if we after all decide to take this path, we will have to implement an opt-in solution. |
wshanks commentedJan 21, 2025
I think the absence of |
yaelbh commentedJan 27, 2025
It seems that the concern about the expression not being able to be consumed by the stack is false. The following program runs well: fromqiskit.circuitimportQuantumCircuit,Parameterfromqiskit.transpiler.passmanagerimportPassManagerfromqiskit_ibm_runtimeimportQiskitRuntimeService,SamplerV2fromqiskit_ibm_runtime.transpiler.passes.basisimportFoldRzzAngleservice=QiskitRuntimeService()backend=service.backend("ibm_aachen",use_fractional_gates=True)sampler=SamplerV2(mode=backend)p=Parameter("p")circ=QuantumCircuit(2,2)circ.rzz(p,0,1)circ.measure([0,1], [0,1])pm=PassManager([FoldRzzAngle()])circ=pm.run(circ)# The circuit after the pass contains global phase gates,# which have to be yet taken care of before submitting to the device.# Since we are only curious to see if our generated expression can be consumed,# it is enough to take the `rzz` instruction of the transpiled circiut.print(circ.data)circ.data= [circ.data[4]]job=sampler.run([(circ,-1)])print(job.job_id())res=job.result()print(res[0].data.c.get_counts()) By the way, if we take the pass manager from the plugin, pm=generate_preset_pass_manager(optimization_level=0,backend=backend,translation_method="ibm_fractional",) then the transpilation takes the path of using |
yaelbh commentedJan 28, 2025
After implementing the optimizations,@wshanks's famous Details section shrinks from 8079 to 1943 characters: |
ElePT commentedJul 17, 2025
I understand that this PR will be superseded by#2125 and there are no immediate plans to continue developing it, I will mark it as on hold for the time being. Let me know if this is incorrect. |
yaelbh commentedJul 17, 2025
It's fine to mark it on hold. Just for accuracy,#2125 doesn't supersede this PR, but solves the same problem in a different way. |
Closes#2032.
The transpiler pass of#2043 is extended to accommodate unbounded parameters, including parameter expressions.
Many thanks to Liran Shirizly for the idea.
The tests are currently failing - I'm investigating - opening in draft mode.