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

Strange Behaviour of sx gate when defined inline in QASM #12167

Open
DanBlackwell opened this issue Apr 10, 2024 · 14 comments · May be fixed by #12387
Open

Strange Behaviour of sx gate when defined inline in QASM #12167

DanBlackwell opened this issue Apr 10, 2024 · 14 comments · May be fixed by #12387
Labels
bug Something isn't working mod: qasm3 Related to OpenQASM 3 import or export

Comments

@DanBlackwell
Copy link

Environment

  • Qiskit version: 1.0.2
  • Python version: Python 3.10.12
  • Operating system: Ubuntu 22.04

What is happening?

Applying the sx gate seems to give a different result if I copy and paste the x and sx gate definitions out from stdgates.inc, versus if I use include stdgates.inc.

How can we reproduce the issue?

from qiskit import transpile
from qiskit.qasm3 import loads
from qiskit.quantum_info import Statevector
from qiskit_aer import Aer

qc = loads('''
OPENQASM 3.0;
gate x a { U(pi, 0, pi) a; }
gate sx a { pow(1/2) @ x a; }
qubit[1] r1;
sx r1[0];
''')
qc = transpile(qc, Aer.get_backend('qasm_simulator'))
state_vec = Statevector.from_instruction(qc)
print(state_vec)
print(state_vec.probabilities())

Output:

Statevector([1.+0.j, 0.+0.j],
            dims=(2,))
[1. 0.]

What should happen?

Using the include instead:

from qiskit import transpile
from qiskit.qasm3 import loads
from qiskit.quantum_info import Statevector
from qiskit_aer import Aer

qc = loads('''
OPENQASM 3.0;
include "stdgates.inc";
qubit[1] r1;
sx r1[0];
''')
qc = transpile(qc, Aer.get_backend('qasm_simulator'))
state_vec = Statevector.from_instruction(qc)
print(state_vec)
print(state_vec.probabilities())

Gets the correct probabilities:

Statevector([0.5+0.5j, 0.5-0.5j],
            dims=(2,))
[0.5 0.5]

Any suggestions?

No response

@DanBlackwell DanBlackwell added the bug Something isn't working label Apr 10, 2024
@levbishop
Copy link
Member

I think perhaps this is happening because the pow(1/2) is being evaluated with integer math and resolving as pow(0)

@jakelishman
Copy link
Member

Lev: it is, I was halfway through typing that haha. It's potentially a vagueness in the OQ3 spec, or alternatively a typo in the OQ3 example, and it should be 1./2 or the like.

@DanBlackwell
Copy link
Author

If it's any help, running the 'broken' QASM through braket and quantastica simulators give the correct result, so I guess they are doing float eval behind the scenes.

@levbishop
Copy link
Member

Yeah I think by the openqasm spec as written, the bug is with the qasm (and, I guess by extension there are bugs with braket/quantastica) https://openqasm.com/language/types.html#casting-specifics

@DanBlackwell
Copy link
Author

I agree that I'd read it that way; though to be pedantic the spec only mentions "promotion and conversion in mixed expressions and assignments", and I can only see a specific mention of integer division referred to for angles.

@DanBlackwell
Copy link
Author

Additionally, are there implementation defined limits on the size of the values? I can produce nan probabillities with the following:

from qiskit import transpile
from qiskit.qasm3 import loads
from qiskit.quantum_info import Statevector
from qiskit_aer import Aer

qc = loads('''
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] r1;
rz(3.15e+32767) r1;
''')
qc = transpile(qc, Aer.get_backend('qasm_simulator'))
state_vec = Statevector.from_instruction(qc)
print(state_vec)
print(state_vec.probabilities())
Statevector([nan+nanj, nan+nanj, nan+nanj, nan+nanj],
            dims=(2, 2))
[nan nan nan nan]

@jakelishman
Copy link
Member

1/2 isn't a mixed expression: it's division of one integer by another as 1 and 2 are both integer literals, and the result is integer division. The result of that is used in an "angle"/"float" context, so we first do the integer division 1/2 -> 0 and then promote 0 to float 0.0. It's likely that the other implementations are (incorrectly) evaluating OpenQASM 3 expressions using Python 3 semantics, where 1/2 is a float (as opposed to Python 2, where it still would have been an integer). If you change it to 1./2, now the 1. is a floating-point literal, and 1./2 is a mixed expression, so the 2 gets promoted to 2. and the division is done as a floating-point thing.

For 3.15e+32767: that's a floating-point literal where the "closest" IEEE-754 double to the real-number mathematical value is inf, so the expected interpretation of that literal is inf. When you do then do statevector simulation with an RZ gate whose angle is inf, you end up with things like exp(1j * inf), which is nan (several expressions with inf produce nan). That's also expected behaviour, and something OpenQASM 3's special angle type - not yet supported by Qiskit - is meant to make easier.

@DanBlackwell
Copy link
Author

Ok it's IEEE-754 double, thanks for all your help!

@jakelishman
Copy link
Member

Technically OQ doesn't specify the floating-point width of floating-point literals (as far as I remember), but in practice I'd be surprised if there's any implementation out there that doesn't use double for the literals. Fwiw, 3.15e+32767 would be inf even in quadruple precision, and in octuple precision it'd be meaningless as an angle because the mantissa wouldn't have enough precision to have stored the x % (2.*pi) component (which is the only meaningful part for an angle).

@DanBlackwell
Copy link
Author

I suppose that these huge angles are not realistic (I am autogenerating programs, hence the weirdness); it may help for troubleshooting in the future to add a stderr warning if a supplied angle seems unrealistically large or cannot be stored at full precision (as the C compilers do).

Anyway, the original reason I opened this issue seems to be a typo in stdgates so I guess we're getting off-topic.

@DanBlackwell
Copy link
Author

Ok, one last thing (I hope) - does the openQASM spec specify whether operations of the same precedence evaluated left-to-right (including casts)? e.g. by C specification with left-to-right eval, 1 / 2 / 1.0 would be (1 / 2) / 1.0 => 0 / 1.0 => 0.0

@levbishop
Copy link
Member

Yes OQ does specify left-to-right evaluation https://openqasm.com/language/classical.html#evaluation-order so I believe (1 / 2) / 1.0 => 0 / 1.0 => 0.0 is indeed the compliant behavior.

@jakelishman
Copy link
Member

Huh, I could have sworn there was a line about associativity in the spec, especially about the power operator. We should fix that - "left to right" is imprecise, and not everything ought to be left-associative. The ANTLR grammar for sure associates power to the right.

@DanBlackwell
Copy link
Author

Hi, just a follow up on this that's tangentially related; but I don't think is worth creating a new issue for.

Can bit strings be treated as ‘integer’ type literals in openQASM3? Reading the spec (https://openqasm.com/language/types.html#literals), it seems that they are syntactic sugar for bracketed array literals (ie ”101” == {1,0,1}). I ask because the following program seems to run fine when importing through qiskit (and it seems as though it is treating ”101” as though 0b101), and it has left me a little confused as to what the difference is:

OPENQASM 3.0;
include "stdgates.inc";
qubit["100"] r1;
h r1["1”];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working mod: qasm3 Related to OpenQASM 3 import or export
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants