`Circuit.from_ir` not supporting observables on physical qubits
Describe the bug
When the openqasm IR includes #pragma braket result expectation z($0) @ z($1), Circuit.from_ir throws error line 1:28 no viable alternative at input 'z($0'.
This error only happens to physical qubits. When using observables on virtual qubits, there is no error.
To reproduce
qasm_program = """
OPENQASM 3.0;
#pragma braket verbatim
box{
gpi2(6.283185307179586) $1;
gpi2(6.283185307179586) $0;
ms(4.397592653589793, 0.0) $0, $1;
}
#pragma braket result expectation z($0) @ z($1)
"""
circuit = Circuit.from_ir(qasm_program)
print(circuit)
Expected behavior Returns a Braket circuit that represents the QASM program above.
Screenshots or logs
line 1:28 no viable alternative at input 'z($0'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[62], line 12
1 qasm_program = """
2 OPENQASM 3.0;
3 #pragma braket verbatim
(...)
9 #pragma braket result expectation z($0) @ z($1)
10 """
---> 12 circuit = Circuit.from_ir(qasm_program)
13 print(circuit)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/circuits/circuit.py:1175, in Circuit.from_ir(source, inputs)
1172 source = source.source
1173 from braket.circuits.braket_program_context import BraketProgramContext
-> 1175 return Interpreter(BraketProgramContext()).build_circuit(
1176 source=source,
1177 inputs=inputs,
1178 is_file=False,
1179 )
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:130, in Interpreter.build_circuit(self, source, inputs, is_file)
126 def build_circuit(
127 self, source: str, inputs: Optional[dict[str, io_type]] = None, is_file: bool = False
128 ) -> Circuit:
129 """Interpret an OpenQASM program and build a Circuit IR."""
--> 130 return self.run(source, inputs, is_file).circuit
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:145, in Interpreter.run(self, source, inputs, is_file)
143 program = parse(source)
144 self._uses_advanced_language_features = False
--> 145 self.visit(program)
146 if self._uses_advanced_language_features:
147 self.logger.warning(
148 "This program uses OpenQASM language features that may "
149 "not be supported on QPUs or on-demand simulators."
150 )
File ~/miniconda/lib/python3.10/functools.py:926, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
924 def _method(*args, **kwargs):
925 method = self.dispatcher.dispatch(args[0].__class__)
--> 926 return method.__get__(obj, cls)(*args, **kwargs)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:172, in Interpreter._(self, node)
170 @visit.register
171 def _(self, node: Program) -> None:
--> 172 self.visit(node.statements)
File ~/miniconda/lib/python3.10/functools.py:926, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
924 def _method(*args, **kwargs):
925 method = self.dispatcher.dispatch(args[0].__class__)
--> 926 return method.__get__(obj, cls)(*args, **kwargs)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:168, in Interpreter._(self, node_list)
165 @visit.register
166 def _(self, node_list: list) -> list[QASMNode]:
167 """Generic visit function for a list of AST nodes"""
--> 168 return [n for n in [self.visit(node) for node in node_list] if n is not None]
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:168, in <listcomp>(.0)
165 @visit.register
166 def _(self, node_list: list) -> list[QASMNode]:
167 """Generic visit function for a list of AST nodes"""
--> 168 return [n for n in [self.visit(node) for node in node_list] if n is not None]
File ~/miniconda/lib/python3.10/functools.py:926, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
924 def _method(*args, **kwargs):
925 method = self.dispatcher.dispatch(args[0].__class__)
--> 926 return method.__get__(obj, cls)(*args, **kwargs)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/interpreter.py:543, in Interpreter._(self, node)
541 @visit.register
542 def _(self, node: Pragma) -> None:
--> 543 parsed = self.context.parse_pragma(node.command)
544 if node.command.startswith("braket result"):
545 if not parsed:
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/program_context.py:444, in AbstractProgramContext.parse_pragma(self, pragma_body)
437 def parse_pragma(self, pragma_body: str):
438 """
439 Parse pragma
440
441 Args:
442 pragma_body (str): The body of the pragma statement.
443 """
--> 444 return parse_braket_pragma(pragma_body, self.qubit_mapping)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/braket_pragmas.py:216, in parse_braket_pragma(pragma_body, qubit_table)
214 parser = BraketPragmasParser(stream)
215 tree = parser.braketPragma()
--> 216 visited = BraketPragmaNodeVisitor(qubit_table).visit(tree)
217 return visited
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/antlr4/tree/Tree.py:34, in ParseTreeVisitor.visit(self, tree)
33 def visit(self, tree):
---> 34 return tree.accept(self)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParser.py:861, in BraketPragmasParser.BraketPragmaContext.accept(self, visitor)
859 def accept(self, visitor:ParseTreeVisitor):
860 if hasattr( visitor, "visitBraketPragma" ):
--> 861 return visitor.visitBraketPragma(self)
862 else:
863 return visitor.visitChildren(self)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParserVisitor.py:14, in BraketPragmasParserVisitor.visitBraketPragma(self, ctx)
13 def visitBraketPragma(self, ctx:BraketPragmasParser.BraketPragmaContext):
---> 14 return self.visitChildren(ctx)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/antlr4/tree/Tree.py:44, in ParseTreeVisitor.visitChildren(self, node)
41 return result
43 c = node.getChild(i)
---> 44 childResult = c.accept(self)
45 result = self.aggregateResult(result, childResult)
47 return result
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParser.py:1226, in BraketPragmasParser.BraketResultPragmaContext.accept(self, visitor)
1224 def accept(self, visitor:ParseTreeVisitor):
1225 if hasattr( visitor, "visitBraketResultPragma" ):
-> 1226 return visitor.visitBraketResultPragma(self)
1227 else:
1228 return visitor.visitChildren(self)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParserVisitor.py:39, in BraketPragmasParserVisitor.visitBraketResultPragma(self, ctx)
38 def visitBraketResultPragma(self, ctx:BraketPragmasParser.BraketResultPragmaContext):
---> 39 return self.visitChildren(ctx)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/antlr4/tree/Tree.py:44, in ParseTreeVisitor.visitChildren(self, node)
41 return result
43 c = node.getChild(i)
---> 44 childResult = c.accept(self)
45 result = self.aggregateResult(result, childResult)
47 return result
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParser.py:1290, in BraketPragmasParser.ResultTypeContext.accept(self, visitor)
1288 def accept(self, visitor:ParseTreeVisitor):
1289 if hasattr( visitor, "visitResultType" ):
-> 1290 return visitor.visitResultType(self)
1291 else:
1292 return visitor.visitChildren(self)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParserVisitor.py:44, in BraketPragmasParserVisitor.visitResultType(self, ctx)
43 def visitResultType(self, ctx:BraketPragmasParser.ResultTypeContext):
---> 44 return self.visitChildren(ctx)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/antlr4/tree/Tree.py:44, in ParseTreeVisitor.visitChildren(self, node)
41 return result
43 c = node.getChild(i)
---> 44 childResult = c.accept(self)
45 result = self.aggregateResult(result, childResult)
47 return result
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/generated/BraketPragmasParser.py:1867, in BraketPragmasParser.ObservableResultTypeContext.accept(self, visitor)
1865 def accept(self, visitor:ParseTreeVisitor):
1866 if hasattr( visitor, "visitObservableResultType" ):
-> 1867 return visitor.visitObservableResultType(self)
1868 else:
1869 return visitor.visitChildren(self)
File ~/virtual_envs/qpu-onboard/lib/python3.10/site-packages/braket/default_simulator/openqasm/parser/braket_pragmas.py:98, in BraketPragmaNodeVisitor.visitObservableResultType(self, ctx)
92 result_type = ctx.observableResultTypeName().getText()
93 observable_result_type_map = {
94 "expectation": Expectation,
95 "sample": Sample,
96 "variance": Variance,
97 }
---> 98 observables, targets = self.visit(ctx.observable())
99 obs = observable_result_type_map[result_type](targets=targets, observable=observables)
100 return obs
TypeError: cannot unpack non-iterable NoneType object
System information A description of your system. Please provide: amazon-braket-algorithm-library 1.2.0 amazon-braket-default-simulator 1.20.1 amazon-braket-pennylane-plugin 1.12.2 amazon-braket-schemas 1.19.1.post0 amazon-braket-sdk 1.65.2.dev0 Python version**: 3.10.9
Physical qubits and verbatim boxes are not currently supported; we'll need to add the stubs to the default simulator and implement them here.
@speller26 Should we update this issue from bug to enhancement? Edit: or, is there a way to improve the error message?