Skip to content

Commit

Permalink
Grammar refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrieleMessina authored Apr 13, 2024
1 parent bbbf01c commit 68cc2f2
Show file tree
Hide file tree
Showing 15 changed files with 2,193 additions and 1,882 deletions.
8 changes: 5 additions & 3 deletions playground/examples/test.qut
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
qubit a = 0q;
bool b = a;
int a = 10;
int b = -4;

print b;
int c = a + b;

print c;
13 changes: 12 additions & 1 deletion specification/grammar/qutes_lexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ VOID_TYPE : 'void' ;
RETURN : 'return' ;
MULTIPLY : '*' ;
DIVIDE : '/' ;
MODULE : '%' ;
ADD : '+' ;
SUB : '-' ;
NOT : 'not' ;
AND : 'and' ;
OR : 'or' ;
BY : 'by' ;
SWAP : 'swap' ;
PAULIY : 'pauliy' ;
Expand All @@ -33,11 +36,19 @@ MEASURE : 'measure' ;
PRINT : 'print' ;
BARRIER : 'barrier' ;
EQUAL : '==' ;
NOT_EQUAL : '!=' ;
GREATER : '>' ;
GREATEREQUAL : '>=' ;
LOWER : '<' ;
LOWEREQUAL : '<=' ;
ASSIGN : '=' ;
AUTO_INCREMENT : '++' ;
AUTO_DECREMENT : '--' ;
AUTO_SUM : '+=' ;
AUTO_SUB : '-=' ;
AUTO_MULTIPLY : '*=' ;
AUTO_DIVIDE : '/=' ;
AUTO_MODULE : '%=' ;
END_OF_STATEMENT : ';' ;
VAR_STATEMENT : 'var' ;
FOR_STATEMENT : 'for' ;
Expand Down Expand Up @@ -98,7 +109,7 @@ BOOL_LITERAL
;

INT_LITERAL
: DIGIT+
: MATH_SIGN? DIGIT+
;

FLOAT_LITERAL
Expand Down
86 changes: 39 additions & 47 deletions specification/grammar/qutes_parser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ statement
| qualifiedName ASSIGN expr END_OF_STATEMENT #AssignmentStatement
| RETURN expr END_OF_STATEMENT #ReturnStatement
| expr END_OF_STATEMENT #ExpressionStatement
| (MEASURE | BARRIER) #FactStatement
| END_OF_STATEMENT #EmptyStatement
;

functionDeclarationParams
: variableDeclaration (COMMA functionDeclarationParams)?
;
Expand All @@ -33,55 +34,39 @@ variableDeclaration
: variableType variableName (ASSIGN expr)?
;

functionCallParams
: qualifiedName (COMMA functionCallParams)?
;

expr
: term
| functionCall
| test
| parenExpr
| groverExpr
;

groverExpr
: termList op=IN_STATEMENT qualifiedName
;

functionCall //Function name should be a qualifiedName here.
: functionName ROUND_PARENTHESIS_OPEN functionCallParams? ROUND_PARENTHESIS_CLOSE
: ROUND_PARENTHESIS_OPEN expr ROUND_PARENTHESIS_CLOSE #ParentesizeExpression
| literal #LiteralExpression
| qualifiedName #QualifiedNameExpression
// Array access
| functionName ROUND_PARENTHESIS_OPEN functionCallParams? ROUND_PARENTHESIS_CLOSE #FunctionCallExpression
| expr op=(AUTO_INCREMENT | AUTO_DECREMENT) #PostfixOperator
| op=(NOT | ADD | SUB | AUTO_INCREMENT | AUTO_DECREMENT) expr #PrefixOperator
// cast operation
| expr op=(MULTIPLY | DIVIDE | MODULE) expr #MultiplicativeOperator
| expr op=(ADD | SUB) expr #SumOperator
| expr op=(GREATEREQUAL | LOWEREQUAL | GREATER | LOWER ) expr #RelationalOperator
| expr op=(EQUAL | NOT_EQUAL) expr #EqualityOperator
| expr op=AND expr #LogicAndOperator
| expr op=OR expr #LogicOrOperator
// | <assoc = right> expr op=(AUTO_SUM | AUTO_DECREMENT | AUTO_MODULE | AUTO_DIVIDE | AUTO_MODULE) expr #AutoAssignmentOperator
| op=(MCX | MCZ | MCY | SWAP) termList #MultipleUnaryOperator
| op=(PRINT | PAULIY | PAULIZ | HADAMARD | MEASURE) expr #UnaryOperator
| op=MCP termList BY expr #MultipleUnaryPhaseOperator
| termList op=IN_STATEMENT qualifiedName #GroverOperator
;

parenExpr
: ROUND_PARENTHESIS_OPEN expr ROUND_PARENTHESIS_CLOSE
functionCallParams
: (literal | qualifiedName) (COMMA functionCallParams)?
;

test
: term
| term op=(GREATER | LOWER | EQUAL | GREATEREQUAL | LOWEREQUAL) term
termList
: (literal | qualifiedName) (COMMA termList)?
;

term
: term op=(MULTIPLY | DIVIDE) term #BinaryPriorityOperator
| term op=(ADD | SUB) term #BinaryOperator
| op=(PRINT | NOT | PAULIY | PAULIZ | HADAMARD | MEASURE | ADD | SUB) term #UnaryOperator
| op=(MCX | MCZ | MCY | SWAP) termList #MultipleUnaryOperator
| op=MCP termList BY expr #MultipleUnaryPhaseOperator
| (boolean
| integer
| float
| qubit
| quint
| qustring
variableType
: type
| qualifiedName
| MEASURE
| BARRIER
| string) #IdentityOperator
;

termList
: term (COMMA termList)?
;

type
Expand All @@ -95,13 +80,10 @@ type
| VOID_TYPE
;

variableType
: type
| qualifiedName
;

qualifiedName
: SYMBOL_LITERAL (DOT SYMBOL_LITERAL)*
| variableName
| functionName
;

variableName
Expand All @@ -112,6 +94,16 @@ functionName
: SYMBOL_LITERAL
;

literal
: boolean
| integer
| float
| qubit
| quint
| qustring
| string
;

string
: STRING_LITERAL
;
Expand Down
123 changes: 11 additions & 112 deletions src/grammar_frontend/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@
from symbols.symbol import Symbol, SymbolClass
from symbols.scope_handler import ScopeHandlerForSymbolsUpdate
from symbols.variables_handler import VariablesHandler
from symbols.types import Qubit, Quint, QutesDataType
from quantum_circuit import QuantumCircuitHandler
from grammar_frontend.qutes_base_visitor import QutesBaseVisitor
import math

class QutesGrammarExpressionVisitor(QutesBaseVisitor):
def __init__(self, symbols_tree:ScopeTreeNode, quantum_circuit_handler : QuantumCircuitHandler, scope_handler:ScopeHandlerForSymbolsUpdate, variables_handler:VariablesHandler, verbose:bool = False):
super().__init__(symbols_tree, quantum_circuit_handler, scope_handler, variables_handler, verbose)

# Visit a parse tree produced by qutesParser#expr.
def visitExpr(self, ctx:qutes_parser.ExprContext):
return self.__visit("visitExpr", lambda : self.visitChildren(ctx))
return self.visitChildren(ctx)

def visitParentesizeExpression(self, ctx:qutes_parser.ParentesizeExpressionContext):
return self.visitChildren(ctx)

def visitLiteralExpression(self, ctx:qutes_parser.LiteralExpressionContext):
return self.visitChildren(ctx)

def visitQualifiedNameExpression(self, ctx:qutes_parser.QualifiedNameExpressionContext):
return self.visitChildren(ctx)

# Visit a parse tree produced by qutes_parser#functionCall.
def visitFunctionCall(self, ctx:qutes_parser.FunctionCallContext):
def visitFunctionCallExpression(self, ctx:qutes_parser.FunctionCallExpressionContext):
function_name = self.visit(ctx.functionName())
function_params:list[Symbol] = []
if(ctx.functionCallParams()):
Expand Down Expand Up @@ -57,109 +62,3 @@ def __visitFunctionCall(self, function_name, function_params, tokenIndex):

self.scope_handler.end_function()
return result

# Visit a parse tree produced by qutes_parser#functionCallParams.
def visitFunctionCallParams(self, ctx:qutes_parser.FunctionCallParamsContext):
param = self.visit(ctx.qualifiedName())
params = []
if(ctx.functionCallParams()):
params = self.__visit("functionCallParams", lambda : self.visit(ctx.functionCallParams()))
if(not isinstance(params, list)):
params = [params]
params.append(param)
return params[::-1]

# Visit a parse tree produced by qutesParser#parenExpr.
def visitParenExpr(self, ctx:qutes_parser.ParenExprContext):
return self.__visit("visitparenExpr", lambda : self.__visit_paren_expr(ctx))

def __visit_paren_expr(self, ctx:qutes_parser.ParenExprContext):
result = None
if(ctx.expr()):
if(self.log_trace_enabled): print("visitParenExpr -> expr")
result = self.visitChildren(ctx.expr())
return result

# Visit a parse tree produced by qutes_parser#GroverOperator.
def visitGroverExpr(self, ctx:qutes_parser.GroverExprContext):
return self.__visitGroverOperator(ctx)

grover_count = iter(range(1, 1000))
def __visitGroverOperator(self, ctx:qutes_parser.GroverExprContext):
current_grover_count = next(self.grover_count)
target_symbol:Symbol = self.visit(ctx.qualifiedName())
if(not QutesDataType.is_quantum_type(target_symbol.casted_static_type)):
#TODO: Handle promotion to quantum type?
return
if(ctx.IN_STATEMENT()):
array_register = target_symbol.quantum_register
self.quantum_circuit_handler.start_quantum_function()
termList:list[Symbol] = self.visit(ctx.termList())
array_size = len(target_symbol.quantum_register)

grover_result = self.quantum_circuit_handler.declare_quantum_register("grover_phase_ancilla", Qubit())
oracle_registers = [array_register]
registers_to_measure = []
if(self.log_grover_verbose):
registers_to_measure.append(array_register)
rotation_register = None
phase_kickback_ancilla = None

for term in termList:
if(not QutesDataType.is_array_type(target_symbol.casted_static_type)):
self.quantum_circuit_handler.push_equals_operation(array_register, term.value)
if(len(array_register) == 1):
if(phase_kickback_ancilla == None):
phase_kickback_ancilla = self.quantum_circuit_handler.declare_quantum_register(f"phase_kickback_ancilla_{current_grover_count}", Qubit(0,1))
oracle_registers.append(phase_kickback_ancilla)
self.quantum_circuit_handler.push_MCZ_operation([*array_register, phase_kickback_ancilla])
else:
self.quantum_circuit_handler.push_MCZ_operation([*array_register])
self.quantum_circuit_handler.push_equals_operation(array_register, term.value)
else:
term_to_quantum = QutesDataType.promote_classical_to_quantum_value(term.value)
block_size = target_symbol.value.default_block_size
array_size = int(len(target_symbol.quantum_register)/block_size)
logn = max(int(math.log2(array_size)),1)
if(term_to_quantum.size == 1):
if(phase_kickback_ancilla == None):
phase_kickback_ancilla = self.quantum_circuit_handler.declare_quantum_register(f"phase_kickback_ancilla_{current_grover_count}", Qubit(0,1))
oracle_registers.append(phase_kickback_ancilla)
if(rotation_register == None):
rotation_register = self.quantum_circuit_handler.declare_quantum_register(f"rotation(grover:{current_grover_count})", Quint.init_from_integer(0,logn,True))
oracle_registers.append(rotation_register)
if(self.log_grover_verbose):
registers_to_measure.append(rotation_register)
self.quantum_circuit_handler.push_ESM_operation(array_register, rotation_register, term_to_quantum, phase_kickback_ancilla)

oracle_registers.append(grover_result)
quantum_function = self.quantum_circuit_handler.end_quantum_function(*oracle_registers, gate_name=f"grover_oracle_{current_grover_count}", create_gate=False)

qubits_involved_in_grover = [*range(quantum_function.num_qubits)]
if(rotation_register != None):
qubits_involved_in_grover = [*range(quantum_function.num_qubits-len(rotation_register)-1, quantum_function.num_qubits-1), quantum_function.num_qubits-1]

for n_results in range(1, array_size+1):
oracle_result = self.quantum_circuit_handler.push_grover_operation(*oracle_registers, quantum_function=quantum_function, register_involved_indexes=qubits_involved_in_grover, dataset_size=array_size, n_results=n_results, verbose=self.log_grover_verbose)
registers_to_measure.append(oracle_result)
circuit_runs = 3
self.quantum_circuit_handler.get_run_and_measure_results(registers_to_measure.copy(), repetition=circuit_runs)

positive_results = [(index, result) for index, result in enumerate(oracle_result.measured_classical_register.measured_values) if "1" in result]
any_positive_results = len(positive_results) > 0
if (any_positive_results):
if(self.log_grover_verbose and rotation_register.measured_classical_register is not None):
print(f"Solution found with rotation {rotation_register.measured_classical_register.measured_values[positive_results[0][0]]} (for the first hit)")
return True
registers_to_measure.remove(oracle_result)
return False

# Utility method for logging and scaffolding operation
def __visit(self, parent_caller_name, func, push_pop_scope:bool = False):
if(self.log_trace_enabled): print("start " + parent_caller_name)
if(push_pop_scope): self.scope_handler.push_scope()
result = func()
if(push_pop_scope): self.scope_handler.pop_scope()
if(self.log_trace_enabled): print("end " + parent_caller_name)
if(self.log_step_by_step_results_enabled): print(result)
return result
Loading

0 comments on commit 68cc2f2

Please sign in to comment.