def visitCalibrationDefinition( self, ctx: qasm3Parser.CalibrationDefinitionContext): # TODO: Possible grammar improvement. The current grammar return the body as a token # stream. We reconstruct the body by concat the tokens space delimiter. # This will not exactly reproduce the body but it can be parsed by another grammar. body_chars = [ ] # Python concatenation is slow so we build a list first for i in range(ctx.getChildCount() - 2, 0, -1): node = ctx.getChild(i) if isinstance(node, TerminalNode): body_chars.insert(0, node.getText()) else: break name = add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier())) return CalibrationDefinition( name=name, arguments=self.visit(ctx.calibrationArgumentList().getChild(0)) if ctx.calibrationArgumentList() else [], qubits=[ add_span(Identifier(id.getText()), get_span(id)) for id in ctx.identifierList().Identifier() ], return_type=self.visit(ctx.returnSignature().classicalType()) if ctx.returnSignature() else None, body=" ".join(body_chars[1:]), )
def test_header(): p = """ OPENQASM 3.1; include "qelib1.inc"; input angle[16] variable1; output angle[16] variable2; """.strip() program = parse(p) expected = "3.1" assert program.version == expected assert program.includes == [Include("qelib1.inc")] assert program.io_variables == [ IODeclaration( io_identifier=IOKeyword["input"], type=AngleType(size=IntegerLiteral(value=16)), identifier=Identifier(name="variable1"), init_expression=None, ), IODeclaration( io_identifier=IOKeyword["output"], type=AngleType(size=IntegerLiteral(value=16)), identifier=Identifier(name="variable2"), init_expression=None, ), ]
def test_concatenation(): p = """ let a = b[1:1:10] ++ c; """.strip() program = parse(p) assert program == Program(statements=[ AliasStatement( target=Identifier(name="a"), value=Concatenation( lhs=Slice( name="b", range=RangeDefinition( start=IntegerLiteral(value=1), end=IntegerLiteral(value=10), step=IntegerLiteral(value=1), ), ), rhs=Identifier(name="c"), ), ) ]) SpanGuard().visit(program) slice_ = program.statements[0] assert slice_.span == Span(1, 0, 1, 22) assert slice_.target.span == Span(1, 4, 1, 4) assert slice_.value.span == Span(1, 8, 1, 21)
def test_box(): p = """ box [maxdur] { delay[start_stretch] $0; x $0; } """.strip() program = parse(p) assert program == Program(statements=[ Box( duration=Identifier("maxdur"), body=[ DelayInstruction( arguments=[], duration=Identifier("start_stretch"), qubits=[Identifier("$0")], ), QuantumGate(modifiers=[], name=Identifier("x"), arguments=[], qubits=[Identifier("$0")]), ], ) ]) SpanGuard().visit(program)
def test_slice(): p = """ let a = b[1:1:10]; let c = d[1:10]; """.strip() program = parse(p) assert program == Program(statements=[ AliasStatement( target=Identifier(name="a"), value=Slice( name="b", range=RangeDefinition( start=IntegerLiteral(value=1), end=IntegerLiteral(value=10), step=IntegerLiteral(value=1), ), ), ), AliasStatement( target=Identifier(name="c"), value=Slice( name="d", range=RangeDefinition( start=IntegerLiteral(value=1), end=IntegerLiteral(value=10), step=None, ), ), ), ]) SpanGuard().visit(program) slice_ = program.statements[0] assert slice_.span == Span(1, 0, 1, 17) assert slice_.target.span == Span(1, 4, 1, 4) assert slice_.value.span == Span(1, 8, 1, 16)
def test_branch_statement(): p = """ if(temp == 1) { ry(pi / 2) q; } else continue; """.strip() program = parse(p) assert program == Program(statements=[ BranchingStatement( condition=BinaryExpression( op=BinaryOperator["=="], lhs=Identifier("temp"), rhs=IntegerLiteral(1), ), if_block=[ QuantumGate( modifiers=[], name=Identifier("ry"), arguments=[ BinaryExpression( op=BinaryOperator["/"], lhs=Constant(ConstantName.pi), rhs=IntegerLiteral(2), ) ], qubits=[Identifier("q")], ), ], else_block=[ContinueStatement()], ) ]) SpanGuard().visit(program)
def test_measurement(): p = """ measure q; measure q -> c[0]; c[0] = measure q[0]; """.strip() program = parse(p) assert program == Program(statements=[ QuantumMeasurementAssignment(target=None, measure_instruction=QuantumMeasurement( qubit=Identifier("q"))), QuantumMeasurementAssignment( target=IndexedIdentifier( name=Identifier(name="c"), indices=[[IntegerLiteral(value=0)]], ), measure_instruction=QuantumMeasurement(qubit=Identifier("q")), ), QuantumMeasurementAssignment( target=IndexedIdentifier( name=Identifier(name="c"), indices=[[IntegerLiteral(value=0)]], ), measure_instruction=QuantumMeasurement(qubit=IndexedIdentifier( name=Identifier("q"), indices=[[IntegerLiteral(value=0)]], ), ), ), ]) SpanGuard().visit(program)
def test_gate_calls(): p = """ qubit q; qubit r; h q; cx q, r; inv @ h q; """.strip() # TODO Add "ctrl @ pow(power) @ phase(theta) q, r;" after we complete expressions program = parse(p) assert program == Program(statements=[ QubitDeclaration(qubit=Identifier(name="q"), size=None), QubitDeclaration(qubit=Identifier(name="r"), size=None), QuantumGate(modifiers=[], name=Identifier("h"), arguments=[], qubits=[Identifier(name="q")]), QuantumGate( modifiers=[], name=Identifier("cx"), arguments=[], qubits=[Identifier(name="q"), Identifier(name="r")], ), QuantumGate( modifiers=[ QuantumGateModifier(modifier=GateModifierName["inv"], argument=None) ], name=Identifier("h"), arguments=[], qubits=[Identifier(name="q")], ), ], ) SpanGuard().visit(program)
def test_qubit_and_bit_declaration(): p = """ bit c; qubit a; """.strip() program = parse(p) assert program == Program(statements=[ ClassicalDeclaration(BitType(None), Identifier("c"), None), QubitDeclaration(qubit=Identifier(name="a"), size=None), ]) SpanGuard().visit(program)
def test_array_declaration(): p = """ array[uint[8], 2] a; array[int[8], 2] a = {1, 1}; array[bit, 2] a = b; array[float[32], 2, 2] a; array[complex[float[64]], 2, 2] a = {{1, 1}, {2, 2}}; array[uint[8], 2, 2] a = {b, b}; """.strip() program = parse(p) a, b = Identifier("a"), Identifier("b") one, two, eight = IntegerLiteral(1), IntegerLiteral(2), IntegerLiteral(8) SpanGuard().visit(program) assert program == Program(statements=[ ClassicalDeclaration( type=ArrayType(base_type=UintType(eight), dimensions=[two]), identifier=a, init_expression=None, ), ClassicalDeclaration( type=ArrayType(base_type=IntType(eight), dimensions=[two]), identifier=a, init_expression=ArrayLiteral([one, one]), ), ClassicalDeclaration( type=ArrayType(base_type=BitType(size=None), dimensions=[two]), identifier=a, init_expression=b, ), ClassicalDeclaration( type=ArrayType( base_type=FloatType(IntegerLiteral(32)), dimensions=[two, two], ), identifier=a, init_expression=None, ), ClassicalDeclaration( type=ArrayType( base_type=ComplexType(FloatType(IntegerLiteral(64))), dimensions=[two, two], ), identifier=a, init_expression=ArrayLiteral( [ArrayLiteral([one, one]), ArrayLiteral([two, two])], ), ), ClassicalDeclaration( type=ArrayType(base_type=UintType(eight), dimensions=[two, two]), identifier=a, init_expression=ArrayLiteral([b, b]), ), ], )
def test_alias_statement(): p = """ let a = b; """.strip() program = parse(p) assert program == Program(statements=[ AliasStatement(target=Identifier(name="a"), value=Identifier(name="b")) ]) SpanGuard().visit(program) alias_statement = program.statements[0] assert alias_statement.span == Span(1, 0, 1, 9) assert alias_statement.target.span == Span(1, 4, 1, 4) assert alias_statement.value.span == Span(1, 8, 1, 8)
def test_delay_instruction(): p = """ delay[start_stretch] $0; """.strip() program = parse(p) assert program == Program(statements=[ DelayInstruction( arguments=[], duration=Identifier("start_stretch"), qubits=[Identifier("$0")], ) ]) SpanGuard().visit(program)
def test_single_gatecall(): p = """ h q; """.strip() program = parse(p) assert program == Program(statements=[ QuantumGate(modifiers=[], name=Identifier("h"), arguments=[], qubits=[Identifier(name="q")]) ]) SpanGuard().visit(program) quantum_gate = program.statements[0] assert quantum_gate.span == Span(1, 0, 1, 3) assert quantum_gate.qubits[0].span == Span(1, 2, 1, 2)
def test_no_designator_type(): p = """ duration a; stretch b; """.strip() program = parse(p) assert program == Program(statements=[ ClassicalDeclaration( DurationType(), Identifier("a"), None, ), ClassicalDeclaration(StretchType(), Identifier("b"), None), ]) SpanGuard().visit(program)
def test_pramga(): p = """ #pragma {verbatim;} #pragma {my_statement1; my_statement2;} end; """.strip() program = parse(p) assert program == Program(statements=[ Pragma(statements=[ExpressionStatement(Identifier("verbatim"))]), Pragma(statements=[ ExpressionStatement(Identifier("my_statement1")), ExpressionStatement(Identifier("my_statement2")), ]), EndStatement(), ]) SpanGuard().visit(program)
def test_durationof(): p = """ durationof({x $0;}) """.strip() program = parse(p) assert program == Program(statements=[ ExpressionStatement(expression=DurationOf(target=[ QuantumGate( modifiers=[], name=Identifier("x"), arguments=[], qubits=[Identifier("$0")], ), ])) ]) SpanGuard().visit(program)
def visitBuiltInCall(self, ctx: qasm3Parser.BuiltInCallContext): if ctx.builtInMath(): return FunctionCall( self.visit(ctx.builtInMath()), [ self.visit(expression) for expression in ctx.expressionList().expression() ], ) if ctx.SIZEOF(): name = add_span(Identifier(name=ctx.SIZEOF().getText()), get_span(ctx.SIZEOF())) return FunctionCall( name, [ self.visit(expression) for expression in ctx.expressionList().expression() ], ) if ctx.castOperator(): return Cast( self.visit(ctx.castOperator().classicalType()), [ self.visit(expression) for expression in ctx.expressionList().expression() ], )
def visitClassicalArgument(self, ctx: qasm3Parser.ClassicalArgumentContext): if ctx.singleDesignatorType(): type_name = ctx.singleDesignatorType().getText() if type_name in _TYPE_NODE_INIT: type_size = self.visit(ctx.designator()) type_node = _TYPE_NODE_INIT[type_name](type_size) else: # To capture potential parser error. raise ValueError("Type name {type_name} not found.") classcal_type = add_span( type_node, combine_span(get_span(ctx.singleDesignatorType()), get_span(ctx.designator())), ) elif ctx.noDesignatorType(): classcal_type = self.visit(ctx.noDesignatorType()) else: classcal_type = add_span( BitType( self.visit(ctx.designator()) if ctx.designator() else None, ), get_span(ctx.getChild(0)), ) identifier = add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier())) return ClassicalArgument(classcal_type, identifier)
def visitExpressionTerminator( self, ctx: qasm3Parser.ExpressionTerminatorContext): if ctx.Constant(): const_text = ctx.Constant().getText() if const_text == "π": const_name = ConstantName.pi elif const_text == "𝜏": const_name = ConstantName.tau elif const_text == "ℇ": const_name = ConstantName.euler else: const_name = ConstantName[const_text] return Constant(const_name) elif ctx.Integer(): return IntegerLiteral(int(ctx.Integer().getText())) elif ctx.RealNumber(): return RealLiteral(float(ctx.RealNumber().getText())) elif ctx.booleanLiteral(): return BooleanLiteral(True if ctx.booleanLiteral().getText() == "true" else False) elif ctx.Identifier(): return Identifier(ctx.Identifier().getText()) elif ctx.StringLiteral(): return StringLiteral(ctx.StringLiteral().getText()[1:-1]) elif ctx.builtInCall(): return self.visit(ctx.builtInCall()) elif ctx.externOrSubroutineCall(): return self.visit(ctx.externOrSubroutineCall()) elif ctx.timingIdentifier(): return self.visit(ctx.timingIdentifier()) elif ctx.LPAREN(): return self.visit(ctx.expression()) elif ctx.expressionTerminator(): return IndexExpression(self.visit(ctx.expressionTerminator()), self.visit(ctx.expression()))
def visitTimingIdentifier(self, ctx: qasm3Parser.TimingIdentifierContext): if ctx.TimingLiteral(): # parse timing literal s = ctx.TimingLiteral().getText() if s[-2:] in ["dt", "ns", "us", "ms"]: duration_literal = DurationLiteral(float(s[:-2]), TimeUnit[s[-2:]]) elif s[-2:] == "µs": duration_literal = DurationLiteral(float(s[:-2]), TimeUnit["us"]) else: # Must be "s" duration_literal = DurationLiteral(float(s[:-1]), TimeUnit["s"]) return duration_literal elif ctx.Identifier(): return DurationOf( target=add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier()))) else: child_count = ctx.quantumBlock().getChildCount() return DurationOf(target=[ self.visit(ctx.quantumBlock().getChild(i)) for i in range(1, child_count - 1) ])
def visitConstantDeclaration(self, ctx: qasm3Parser.ConstantDeclarationContext): return ConstantDeclaration( identifier=add_span(Identifier(name=ctx.Identifier().getText()), get_span(ctx.Identifier())), init_expression=self.visit(ctx.equalsExpression().expression()), )
def visitIndexIdentifier(self, ctx: qasm3Parser.IndexIdentifierContext): if ctx.Identifier(): name = ctx.Identifier().getText() if ctx.expressionList(): expr_list = [] for expr in ctx.expressionList().expression(): expr_list.append(self.visit(expr)) if len(expr_list) > 1: subscript = Selection(name=name, indices=expr_list) else: subscript = Subscript(name=name, index=expr_list[0]) elif ctx.rangeDefinition(): subscript = Slice(name=name, range=self.visit(ctx.rangeDefinition())) else: return add_span(Identifier(name=ctx.Identifier().getText()), get_span(ctx)) else: id0 = self.visit(ctx.indexIdentifier()[0]) id1 = self.visit(ctx.indexIdentifier()[1]) return Concatenation(lhs=id0, rhs=id1) return subscript
def visitQuantumArgument(self, ctx: qasm3Parser.QuantumArgumentContext): return QuantumArgument( add_span( Identifier(ctx.Identifier().getText(), ), get_span(ctx.Identifier()), ), self.visit(ctx.designator()) if ctx.designator() else None, )
def visitIndexedIdentifier(self, ctx: qasm3Parser.IndexedIdentifierContext): name = add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier())) if not ctx.indexOperator(): return name indices = [self.visit(operator) for operator in ctx.indexOperator()] return IndexedIdentifier(name=name, indices=indices)
def test_qubit_declaration(): p = """ qubit q; qubit[4] a; """.strip() program = parse(p) assert program == Program(statements=[ QubitDeclaration(qubit=Identifier(name="q"), size=None), QubitDeclaration( qubit=Identifier(name="a"), size=IntegerLiteral(4), ), ]) SpanGuard().visit(program) qubit_declaration = program.statements[0] assert qubit_declaration.span == Span(1, 0, 1, 7) assert qubit_declaration.qubit.span == Span(1, 6, 1, 6)
def test_subroutine_definition(): p = """ def ymeasure(qubit q) -> bit { s q; h q; return measure q; } """.strip() program = parse(p) assert program == Program(statements=[ SubroutineDefinition( name=Identifier("ymeasure"), arguments=[QuantumArgument(qubit=Identifier("q"), size=None)], return_type=BitType(None), body=[ QuantumGate( modifiers=[], name=Identifier("s"), arguments=[], qubits=[Identifier(name="q")], ), QuantumGate( modifiers=[], name=Identifier("h"), arguments=[], qubits=[Identifier(name="q")], ), ReturnStatement(expression=QuantumMeasurement(qubit=Identifier( name="q"))), ], ) ]) SpanGuard().visit(program)
def visitExternOrSubroutineCall( self, ctx: qasm3Parser.ExternOrSubroutineCallContext): expressions = ([ self.visit(expression) for expression in ctx.expressionList().expression() ] if ctx.expressionList() else []) name = add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier())) return FunctionCall(name, expressions)
def visitNoDesignatorDeclaration( self, ctx: qasm3Parser.NoDesignatorDeclarationContext): return ClassicalDeclaration( type=self.visit(ctx.noDesignatorType()), identifier=add_span(Identifier(ctx.Identifier().getText()), get_span(ctx.Identifier())), init_expression=self.visit(ctx.equalsExpression().expression()) if ctx.equalsExpression() else None, )
def visitQuantumDeclaration(self, ctx: qasm3Parser.QuantumDeclarationContext): return QubitDeclaration( add_span( Identifier(ctx.Identifier().getText(), ), get_span(ctx.Identifier()), ), self.visit(ctx.designator()) if ctx.designator() else None, )
def visitQuantumGateDefinition( self, ctx: qasm3Parser.QuantumGateDefinitionContext): gate_name = self.visit(ctx.quantumGateSignature().quantumGateName()) gate_arg_lists = ctx.quantumGateSignature().identifierList( ) # argument and qubit lists arguments = ([ add_span(Identifier(arg.getText()), get_span(arg)) for arg in gate_arg_lists[0].Identifier() ] if len(gate_arg_lists) == 2 else []) qubits = [ add_span(Identifier(i.getText()), get_span(i)) for i in gate_arg_lists[-1].Identifier() ] child_count = ctx.quantumBlock().getChildCount() body = [ self.visit(ctx.quantumBlock().getChild(i)) for i in range(1, child_count - 1) ] return QuantumGateDefinition(gate_name, arguments, qubits, body)