Skip to content

Commit

Permalink
Refactor quantum types
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrieleMessina authored Jul 10, 2024
1 parent 0ca479c commit ed0180b
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 56 deletions.
8 changes: 4 additions & 4 deletions src/grammar_frontend/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ def __visit_unary_operator(self, ctx:qutes_parser.UnaryOperatorContext | qutes_p
if(first_term_symbol.symbol_declaration_static_type == QutesDataType.qustring):
index = 0
string_value = ""
while index < first_term_symbol.value.number_of_chars * Qustring.default_char_size:
bin_char = bytes_str[index:Qustring.default_char_size + index]
while index < first_term_symbol.value.number_of_chars * Qustring.default_size_in_qubit:
bin_char = bytes_str[index:Qustring.default_size_in_qubit + index]
string_value = string_value + Qustring.get_char_from_int(int(bin_char, 2))
index = index + Qustring.default_char_size
index = index + Qustring.default_size_in_qubit
print(string_value)
else:
new_value = int(bytes_str, 2)
Expand Down Expand Up @@ -267,7 +267,7 @@ def visitGroverOperator(self, ctx:qutes_parser.GroverOperatorContext):
array_register = target_symbol.quantum_register
block_size = 1
try:
block_size = target_symbol.value.default_block_size
block_size = target_symbol.value.default_size_in_qubit
except:
pass
array_size = int(len(target_symbol.quantum_register)/block_size)
Expand Down
5 changes: 2 additions & 3 deletions src/quantum_circuit/quantum_circuit_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@ def declare_quantum_register(self, variable_name : str, quantum_variable : any)
self._registers_states[new_register] = quantum_variable.get_quantum_state()
return new_register

# TODO: this should be a correlation operation, or a measure and then update.
# We cannot rely on quantum_variable.get_quantum_state()
def replace_quantum_register(self, variable_name : str, quantum_variable : any) -> QuantumRegister:
register_to_update = self._varname_to_register[variable_name]
if(register_to_update is None):
raise SystemError("Error trying to update an undeclared quantum register")

#TODO: can we handle qubit like quint and qustring?
# if(isinstance(quantum_variable, Qubit)):
# pass
if(isinstance(quantum_variable, Qubit) or isinstance(quantum_variable, Quint) or isinstance(quantum_variable, Qustring)):
#TODO-CRITICAL: this update actually change the reference, so all the old references around the code are still there. For now i hack this returning the new value and changing the name from update to replace.
#Delete old quantum register and reference
Expand Down
1 change: 1 addition & 0 deletions src/symbols/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Aliasing for easy importing through the code
from symbols.types.qubit import Qubit
from symbols.types.quantum_type import QuantumType
from symbols.types.quint import Quint
from symbols.types.qustring import Qustring
from symbols.types.qutes_data_type import QutesDataType
15 changes: 15 additions & 0 deletions src/symbols/types/quantum_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from symbols.types import Qubit

class QuantumType:
default_value = [Qubit(complex(1),complex(0))]
default_size_in_qubit = 1
default_superposition_value = [Qubit(complex(0.5),complex(0.5))]

def __init__(self):
pass

def __str__(self) -> str:
return self.__to_printable__()

def __repr__(self) -> str:
return self.__to_printable__()
17 changes: 8 additions & 9 deletions src/symbols/types/qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
import cmath

class Qubit():
default_block_size = 1
def __init__(self, alpha : complex = complex(1), beta : complex = complex(0)):
self.size:int = 1
self.alpha = complex(alpha)
self.beta = complex(beta)
self.phase = Phase.Positive if (alpha * beta).real >= 0 else Phase.Negative
self.is_superposition = cmath.isclose(abs(alpha), abs(beta))
self.qubit_state:list[Qubit] = [self]

def from_string(literal : str) -> 'Qubit':
try:
literal = literal.removesuffix(QutesParser.literal_to_string(QutesParser.QUBIT_LITERAL_POSTFIX))
Expand Down Expand Up @@ -46,14 +53,6 @@ def fromValue(var_value : any) -> 'Qubit':
else:
return Qubit(complex(1), complex(0))
raise TypeError(f"Cannot convert {type(var_value)} to qubit.")

def __init__(self, alpha : complex = complex(1), beta : complex = complex(0)):
self.size:int = 1
self.alpha = complex(alpha)
self.beta = complex(beta)
self.phase = Phase.Positive if (alpha * beta).real >= 0 else Phase.Negative
self.is_superposition = cmath.isclose(abs(alpha), abs(beta))
self.qubit_state:list[Qubit] = [self]

def get_quantum_state(self) -> list[complex]:
return [self.alpha, self.beta]
Expand Down
23 changes: 9 additions & 14 deletions src/symbols/types/quint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
from utils.phase import Phase
import utils
from symbols.types import Qubit
from symbols.types import QuantumType

class Quint():
class Quint(QuantumType):
default_value = [Qubit(complex(1),complex(0))]
default_superposition_value = [Qubit(complex(0.5),complex(0.5))]
default_block_size = 1
default_size_in_qubit = 1

def __init__(self, qubits:list[Qubit] = [Qubit(complex(1),complex(0))]):
super().__init__()
self.qubit_state:list[Qubit] = qubits
self.size:int = len(self.qubit_state)

def init_from_string(literal : str) -> 'Quint':
qubits = []
Expand Down Expand Up @@ -74,11 +80,6 @@ def fromValue(var_value : any) -> 'Quint':
raise TypeError(f"Cannot convert {type(var_value)} to quint.")
except:
raise TypeError(f"Cannot convert {type(var_value)} to quint.")


def __init__(self, qubits:list[Qubit] = [Qubit(complex(1),complex(0))]):
self.qubit_state:list[Qubit] = qubits
self.size:int = len(self.qubit_state)

def get_quantum_state(self) -> list[complex] :
#TODO: this doesn't make any sense, outside of the initialization phase we should not rely on the quantum state.
Expand Down Expand Up @@ -107,10 +108,4 @@ def __to_printable__(self) -> str:
for qubit in self.qubit_state:
str += f"{qubit}, "
str += ']'
return str

def __str__(self) -> str:
return self.__to_printable__()

def __repr__(self) -> str:
return self.__to_printable__()
return str
42 changes: 17 additions & 25 deletions src/symbols/types/qustring.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
from grammar_frontend.qutes_parser import QutesParser
import utils, math
from symbols.types import Qubit, Quint
from symbols.types import QuantumType

class Qustring():
class Qustring(QuantumType):
# note: chr and ord, parse int and char in ASCII for char of size 7 bits
default_value = [Qubit(complex(1),complex(0))]
superposition_char = '*'
not_valid_char = 'X'
# allowed_chars = ['a', 'b', 'c', 'd', superposition_char, not_valid_char]
# allowed_chars = ['0', '1', superposition_char, not_valid_char]
superposition_char = '*'
not_valid_char = 'X'
allowed_chars = ['0', '1']
default_char_size = math.ceil(math.log2(len(allowed_chars)))
default_block_size = default_char_size
default_size_in_qubit = math.ceil(math.log2(len(allowed_chars)))
default_value = [Qubit(complex(1),complex(0))] * default_size_in_qubit
default_superposition_value = [Qubit(complex(0.5),complex(0.5))] * default_size_in_qubit

def __init__(self, qubits:list[Qubit] = [Qubit(complex(1),complex(0))]):
super().__init__()
self.qubit_state:list[Qubit] = qubits
self.size:int = len(self.qubit_state)
self.number_of_chars:int = int(self.size / Qustring.default_size_in_qubit)

def get_char_from_int(int_value:int):
if(int_value > len(Qustring.allowed_chars)):
Expand All @@ -22,8 +29,7 @@ def get_int_from_char(char_value:str):
try:
return Qustring.allowed_chars.index(char_value)
except:
return len(Qustring.allowed_chars)-1

return len(Qustring.allowed_chars)-1

def init_from_string(literal : str) -> 'Qustring':
qubits = []
Expand All @@ -34,26 +40,18 @@ def init_from_string(literal : str) -> 'Qustring':

for char in literal:
if(char == Qustring.superposition_char):
qubyte:Quint = Quint.init_from_integer(Qustring.get_int_from_char(char), Qustring.default_char_size, True)
qubyte:Quint = Quint.init_from_integer(Qustring.get_int_from_char(char), Qustring.default_size_in_qubit, True)
else:
qubyte:Quint = Quint.init_from_integer(Qustring.get_int_from_char(char), Qustring.default_char_size)
qubyte:Quint = Quint.init_from_integer(Qustring.get_int_from_char(char), Qustring.default_size_in_qubit)
qubits.extend(qubyte.qubit_state)
return Qustring(qubits)

def init_from_size(number_of_bits : int) -> 'Qustring':
return Qustring(Qustring.default_value*number_of_bits)

def fromValue(var_value : any) -> 'Qustring':
if(isinstance(var_value, Qubit)):
return Qustring([var_value])
if(isinstance(var_value, str)):
return Qustring.init_from_string(var_value)
raise TypeError(f"Cannot convert {type(var_value)} to quint.")

def __init__(self, qubits:list[Qubit] = [Qubit(complex(1),complex(0))]):
self.qubit_state:list[Qubit] = qubits
self.size:int = len(self.qubit_state)
self.number_of_chars:int = int(self.size / Qustring.default_char_size)

def get_quantum_state(self) -> list[complex] :
#TODO: this doesn't make any sense, outside of the initialization phase we should not rely on the quantum state.
Expand All @@ -76,10 +74,4 @@ def __to_printable__(self) -> str:
for qubit in self.qubit_state:
str += f"{qubit}, "
str += ']'
return str

def __str__(self) -> str:
return self.__to_printable__()

def __repr__(self) -> str:
return self.__to_printable__()
return str
2 changes: 1 addition & 1 deletion src/symbols/types/qutes_data_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def is_array_type(type:'QutesDataType'):
def get_array_word_bit(type:'QutesDataType'):
match type:
case QutesDataType.qustring:
return Qustring.default_char_size
return Qustring.default_size_in_qubit
case _:
return 1

Expand Down

0 comments on commit ed0180b

Please sign in to comment.