Skip to content

Commit

Permalink
Add right and left shift operations to language
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrieleMessina authored Jul 8, 2024
1 parent a55cfef commit 1fadf91
Show file tree
Hide file tree
Showing 13 changed files with 884 additions and 642 deletions.
11 changes: 11 additions & 0 deletions playground/examples/shift_operation.qut
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//Generic Rotation Algorithm (|b| = any)
qustring b = "110111"; //111011 -> 111110
print b;
b << 1;
print b;

//Pavone-Viola Rotation Algorithm (|c| = 2^p)
qustring c = "11011111"; //111011 -> 111110
print c;
c << 1;
print c;
2 changes: 2 additions & 0 deletions specification/grammar/qutes_lexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ GREATER : '>' ;
GREATEREQUAL : '>=' ;
LOWER : '<' ;
LOWEREQUAL : '<=' ;
LSHIFT : '<<' ;
RSHIFT : '>>' ;
ASSIGN : '=' ;
AUTO_INCREMENT : '++' ;
AUTO_DECREMENT : '--' ;
Expand Down
3 changes: 2 additions & 1 deletion specification/grammar/qutes_parser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ variableDeclaration
: variableType variableName (ASSIGN expr)?
;

expr
expr // Order: https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages
: ROUND_PARENTHESIS_OPEN expr ROUND_PARENTHESIS_CLOSE #ParentesizeExpression
| literal #LiteralExpression
| qualifiedName #QualifiedNameExpression
Expand All @@ -45,6 +45,7 @@ expr
// cast operation
| expr op=(MULTIPLY | DIVIDE | MODULE) expr #MultiplicativeOperator
| expr op=(ADD | SUB) expr #SumOperator
| expr op=(LSHIFT | RSHIFT) expr #ShiftOperator
| expr op=(GREATEREQUAL | LOWEREQUAL | GREATER | LOWER ) expr #RelationalOperator
| expr op=(EQUAL | NOT_EQUAL) expr #EqualityOperator
| expr op=AND expr #LogicAndOperator
Expand Down
30 changes: 27 additions & 3 deletions src/grammar_frontend/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ def visitMultiplicativeOperator(self, ctx:qutes_parser.MultiplicativeOperatorCon
return self.__visit_binary_operator(ctx)

def visitSumOperator(self, ctx:qutes_parser.SumOperatorContext):
return self.__visit_binary_operator(ctx)
return self.__visit_binary_operator(ctx)

def visitShiftOperator(self, ctx:qutes_parser.ShiftOperatorContext):
return self.__visit_binary_operator(ctx)

def visitRelationalOperator(self, ctx:qutes_parser.RelationalOperatorContext):
return self.__visit_boolean_operation(ctx)
Expand Down Expand Up @@ -75,6 +78,27 @@ def __visit_binary_operator(self, ctx:qutes_parser.SumOperatorContext | qutes_pa
if (first_term_symbol and QutesDataType.is_quantum_type(first_term_symbol.symbol_declaration_static_type)):
pass
result = first_term_value - second_term_value
if(isinstance(ctx, qutes_parser.ShiftOperatorContext)):
if(ctx.LSHIFT()):
if (first_term_symbol and QutesDataType.is_quantum_type(first_term_symbol.symbol_declaration_static_type)):
if(second_term_symbol and not QutesDataType.is_quantum_type(second_term_symbol.symbol_declaration_static_type)):
from quantum_circuit.qutes_gates import QutesGates
self.quantum_circuit_handler.push_compose_circuit_operation(QutesGates.left_rot(len(first_term_symbol.quantum_register), second_term_value, 1), [first_term_symbol.quantum_register]) #TODO: handle block size
result = first_term_symbol
else:
raise NotImplementedError("Left shift operator doesn't support second term to be a quantum variable.")
else:
result = first_term_value << second_term_value
if(ctx.RSHIFT()):
if (first_term_symbol and QutesDataType.is_quantum_type(first_term_symbol.symbol_declaration_static_type)):
if(second_term_symbol and not QutesDataType.is_quantum_type(second_term_symbol.symbol_declaration_static_type)):
from quantum_circuit.qutes_gates import QutesGates
self.quantum_circuit_handler.push_compose_circuit_operation(QutesGates.right_rot(len(first_term_symbol.quantum_register), second_term_value, 1), [first_term_symbol.quantum_register]) #TODO: handle block size
result = first_term_symbol
else:
raise NotImplementedError("Right shift operator doesn't support second term to be a quantum variable.")
else:
result = first_term_value >> second_term_value
if(isinstance(ctx, qutes_parser.MultiplicativeOperatorContext)):
if(ctx.MULTIPLY()):
if (first_term_symbol and QutesDataType.is_quantum_type(first_term_symbol.symbol_declaration_static_type)):
Expand Down Expand Up @@ -278,7 +302,7 @@ def visitGroverOperator(self, ctx:qutes_parser.GroverOperatorContext):
if(n_element_to_rotate.is_integer() and utils.is_power_of_two(int(n_element_to_rotate))):
logn = max(int(math.log2(n_element_to_rotate)),1)
else:
logn = max(int(math.log2(n_element_to_rotate)+1),1) #TODO: non working with pavone-viola cycling rotation gate
logn = max(int(math.log2(n_element_to_rotate))+1,1)

if(term_to_quantum.size == 1):
if(phase_kickback_ancilla == None):
Expand Down Expand Up @@ -309,7 +333,7 @@ def visitGroverOperator(self, ctx:qutes_parser.GroverOperatorContext):
if (any_positive_results):
if(self.log_grover_esm_rotation and rotation_register.measured_classical_register is not None):
for result in positive_results:
print(f"Solution found with rotation {int(rotation_register.measured_classical_register.measured_values[result[0]], 2)}")
print(f"Solution found with {int(rotation_register.measured_classical_register.measured_values[result[0]], 2)} left rotations")
# print(f"Solution found with rotation {int(rotation_register.measured_classical_register.measured_values[result[0]], 2) % (n_element_to_rotate)}")
return self.variables_handler.create_anonymous_symbol(QutesDataType.bool, True, ctx.start.tokenIndex)
registers_to_measure.remove(oracle_result)
Expand Down
2 changes: 1 addition & 1 deletion src/quantum_circuit/quantum_circuit_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def push_ESM_operation(self, input:QuantumRegister, rotation_register:QuantumReg
self.push_equals_operation(input[:to_match_len], to_match)

for i in range(len(rotation_register))[::-1]:
self.push_compose_circuit_operation(QutesGates.crot(array_len,2**i,Qustring.default_char_size).inverse(), [rotation_register[i], *input])
self.push_compose_circuit_operation(QutesGates.crot(array_len, 2**i, block_size).inverse(), [rotation_register[i], *input])

# It expects the register to put the result into to be the last one in the list
grover_count = iter(range(1, 1000))
Expand Down
73 changes: 56 additions & 17 deletions src/quantum_circuit/qutes_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from quantum_circuit.quantum_circuit_handler import QuantumCircuitHandler
from symbols.types import Qubit, Quint, Qustring, QutesDataType
from qiskit.circuit.library import GroverOperator
import math
import math, utils

class QutesGates():
def __init__(self, ciruit_handler : QuantumCircuitHandler, variables_handler : 'VariablesHandler'):
Expand Down Expand Up @@ -75,26 +75,65 @@ def sum(self, var_a_symbol:'Symbol', var_b_symbol:'Symbol') -> 'Symbol':
return result_symbol

#Rotation gate (not controlled), k=2^p
def rot(n, k, block_size=1):
qc = QuantumCircuit(n, name=f'rot_k={k}')
stop = (int(math.log2(n)) - int(math.log2(k*block_size)) + 2)
for i in range(block_size, stop):
for j in range(0, int(n/(k*(2**i)))):
for x in range(j*k*(2**i), k*((j*2**i+1))):
for offset in range(block_size):
inizio_swap = x + k*offset
fine_swap = x + 2**(i-1)*k + k*offset
qc.swap(inizio_swap, fine_swap)

#qkt.draw_circuit(qc)
rot_gate = qc.to_gate(label='Rot_'+str(k))
def left_rot_power_2(n, k, block_size=1):
qc = QuantumCircuit(n, name=f'rot_power_2_of_{k}')
if(k > 0):
stop = (int(math.log2(n)) - int(math.log2(k*block_size)) + 2)
for i in range(block_size, stop):
for j in range(0, int(n/(k*(2**i)))):
for x in range(j*k*(2**i), k*((j*2**i+1))):
for offset in range(block_size):
inizio_swap = x + k*offset
fine_swap = x + 2**(i-1)*k + k*offset
qc.swap(inizio_swap, fine_swap)
# print(qc.draw(output='text'))
rot_gate = qc.to_gate(label=f'rot_power_2_of_{k}')
return rot_gate

#Rotation gate (not controlled), k=any
def right_rot_generic(n, k, block_size=1):
qc = QuantumCircuit(n, name=f'rot_generic_of_{k}')
if(k > 0):
for w in range(k):
for i in range(0, n-1, block_size):
for j in range(block_size):
qc.swap((i+j)%n, (i+j+1)%n)
# print(qc.draw(output='text'))
rot_gate = qc.to_gate(label=f'rot_generic_of_{k}')
return rot_gate

#Controlled Rotation gate
def crot(n, k, block_size=1):
# Creiamo il gate di rotazione come prima
rot_gate = QutesGates.rot(n, k, block_size)
# Aggiungiamo un qubit di controllo al gate per renderlo controllato
rot_gate = QutesGates.left_rot(n, k, block_size)
c_rot_gate = rot_gate.control(1)
return c_rot_gate

#Right Rotation gate
def right_rot(n, k, block_size=1):
rot_gate = QutesGates.identity(n)
if(utils.is_power_of_two(n)):
if(utils.is_power_of_two(k)):
rot_gate = QutesGates.left_rot_power_2(n, k, block_size).inverse()
else:
# TODO: if k is not power of 2, but n is, then we need to compose multiple left_rot_power_2
rot_gate = QutesGates.right_rot_generic(n, k, block_size)
else:
rot_gate = QutesGates.right_rot_generic(n, k, block_size)
return rot_gate

#Left Rotation gate
def left_rot(n, k, block_size=1):
rot_gate = QutesGates.identity(n)
if(utils.is_power_of_two(n)):
if(utils.is_power_of_two(k)):
rot_gate = QutesGates.left_rot_power_2(n, k, block_size)
else:
# TODO: if k is not power of 2, but n is, then we need to compose multiple left_rot_power_2
rot_gate = QutesGates.right_rot_generic(n, k, block_size).inverse()
else:
rot_gate = QutesGates.right_rot_generic(n, k, block_size).inverse()
return rot_gate

def identity(n):
return QuantumCircuit(n, name=f'identity_{n}').to_gate(label=f'identity_{n}')

Loading

0 comments on commit 1fadf91

Please sign in to comment.