Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions EquationParser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import operator
import re

ops = {
'+': (1, operator.add, 'left'),
'-': (1, operator.sub, 'left'),
'*': (2, operator.mul, 'left'),
'/': (2, operator.truediv, 'left'),
}


class EquationParser:

def __init__(self, variables: dict = None):
self.variables = variables if variables else {}

def add_variable(self, key: str, value: float):
"""Add or update a variable in the dictionary."""
self.variables[key] = value

def remove_variable(self, key: str):
"""Remove a variable from the dictionary."""
if key in self.variables:
del self.variables[key]

def clear_variables(self):
"""Clear all variables from the dictionary."""
self.variables.clear()

@staticmethod
def __tokenize(expression: str) -> list[str]:
"""Tokenize the input expression."""
pattern = r'-?\d+\.\d+|-?\d+|[a-zA-Z_]\w*|[()+\-*/]'
tokens = re.findall(pattern, expression)
return tokens

@staticmethod
def is_is(x):
try:
xx = float(x)
return True
except:
return False

def __convert(self, tokens: list[str]) -> list[str]:
"""Convert the token list into postfix notation using the Shunting-yard algorithm."""
output = []
operators = []

for token in tokens:
if token == '(': # Left parenthesis
operators.append(token)
elif token == ')': # Right parenthesis
while operators and operators[-1] != '(':
output.append(operators.pop())
operators.pop()
elif self.is_is(token) or token in self.variables:
output.append(token)
else:
while operators and operators[-1] != '(' and (
ops[token][0] < ops[operators[-1]][0] or
(ops[token][0] == ops[operators[-1]][0] and ops[token][2] == 'left')
):
output.append(operators.pop())
operators.append(token)

# Append remaining operators
while operators:
output.append(operators.pop())

return output

def __evaluate_postfix(self, postfix: list[str]) -> float:
"""Evaluate the postfix expression."""
stack = []

for token in postfix:
if self.is_is(token):
stack.append(float(token))
elif token in ops: # Apply operators
b = stack.pop()
a = stack.pop()
result = ops[token][1](a, b)
stack.append(result)
else: # Handle variables (Signal or float)
variable = self.variables.get(token, 0)
stack.append(variable)

return stack[0]

def evaluate(self, expression: str):
"""Public method to evaluate a mathematical expression."""
tokens = self.__tokenize(expression)
postfix = self.__convert(tokens)
result = self.__evaluate_postfix(postfix)
return result

# New methods for managing the variables dictionary
12 changes: 12 additions & 0 deletions RunAllTests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from main import setup_gui
from test import test
from Tests.Task1.code import Task1Test
from Tests.Task3.code import QuantizationTest

class RunAllTests:
@staticmethod
def Run():
ob = Task1Test()
ob.Task1TestRunner()
ob2 = QuantizationTest()
ob2.RunAllTests()
123 changes: 123 additions & 0 deletions Signal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import pandas as pd
from math import log2
class Signal:
def __init__(self, data: dict[int, float], offset: float = 0):
"""Initialize the signal with a dictionary of index-value pairs and an offset."""
self.data = dict(sorted(data.items()))
self.offset = offset
self.min_key = min(self.data.keys())
self.max_key = max(self.data.keys())
self.quantized_values = [] # Stores quantized values
self.errors = [] # Stores errors for each quantized value
self.levels = [] # Stores quantization levels
self.encoded_values = [] # Stores encoded binary values for each quantized value

def get_signal_indexs(self):
return list(self.data.keys())

def get_signal_values(self):
return list(self.data.values())
def do_work(self, other, op):
"""Helper function to apply an operation to two Signal objects or a Signal and a scalar."""
if isinstance(other, Signal):
idxs = sorted(set(self.data.keys()).union(other.data.keys()))
result = {}
for i in idxs:
num1 = self.data.get(i, 0)
num2 = other.data.get(i, 0)
result[i] = op(num1, num2)
return Signal(result, offset=self.offset)
elif isinstance(other, (int, float)):
# For scalar operation, apply it to all values in the Signal
result = {i: op(self.data.get(i, 0), other) for i in self.data.keys()}
return Signal(result, offset=self.offset)
else:
return NotImplemented

def __add__(self, other):
return self.do_work(other, lambda x, y: x + y)

def __sub__(self, other):
return self.do_work(other, lambda x, y: x - y)

def __mul__(self, other):
return self.do_work(other, lambda x, y: x * y)

def __truediv__(self, other):
return self.do_work(other, lambda x, y: x / y if y != 0 else float('inf'))

def DelayingOrAdvancingSignalByK(self, k: int):
result = {}
for kk, v in self.data.items():
result[kk + k] = v
self.data = result



def mirror(self):
result = {}
for k, v in self.data.items():
result[k * -1] = v
self.data = dict(sorted(result.items()))


def __repr__(self):
return f"Signal(data={self.data}, offset={self.offset})"

def quantize_signal(self,perception=2, level=None, bits=None):
"""Perform signal quantization and store results in the class."""
if not self.data:
print("No signal data available.")
return

# Convert data values to a list for easier processing
data_values = list(self.data.values())

# Calculate minimum and maximum values from data
min_val = min(data_values)
max_val = max(data_values)

# Determine levels based on the input (either number of levels or bits)
if level is not None:
levels = level
elif bits is not None:
levels = (1 << bits)
else:
print("Provide either levels or bits for quantization.")
return

# Calculate the delta and the actual quantization levels
delta = (max_val - min_val) / levels
self.levels = [round(min_val + i * delta + delta / 2,perception) for i in range(levels)]

# Calculate binary representations of levels
level_bits = int(log2(levels))
binary_reprs = [bin(i)[2:].zfill(level_bits) for i in range(levels)]

# Initialize lists to store quantization outputs and errors
interval_indices = []
encoded_values = []
quantized_values = []
errors = []
output = []
# Perform quantization
for point in data_values:
err = int(1e15)
x = 0
for i in range(levels):
if round(abs(point - self.levels[i]), perception) < err:
x = i
err = round(abs(point - self.levels[i]), perception)
output.append([x + 1, binary_reprs[x], round(self.levels[x], perception), round(self.levels[x] - point, perception)])
interval_indices.append(x + 1)
encoded_values.append(binary_reprs[x])
quantized_values.append(round(self.levels[x], perception))
errors.append(round(self.levels[x] - point, perception))
self.interval_indices= interval_indices
self.quantized_values = quantized_values
self.errors = errors
self.levels = self.levels
self.encoded_values = encoded_values
# Output the quantization details
# output = list(zip(interval_indices, encoded_values, quantized_values, errors))

15 changes: 15 additions & 0 deletions Tests/Task1/Signal1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
0
0
12
-4 -2
-3 2
-2 0
-1 2
0 4
1 6
2 3
3 1
4 -1
5 -3
6 0
7 2
13 changes: 13 additions & 0 deletions Tests/Task1/Signal2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
0
0
10
-3 1
-2 0
-1 -1
0 3
1 2
2 1
3 -3
4 6
5 8
6 3
Binary file added Tests/Task1/__pycache__/code.cpython-312.pyc
Binary file not shown.
15 changes: 15 additions & 0 deletions Tests/Task1/add.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
0
0
12
-4 -2
-3 3
-2 0
-1 1
0 7
1 8
2 4
3 -2
4 5
5 5
6 3
7 2
15 changes: 15 additions & 0 deletions Tests/Task1/advance3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
0
0
12
-7 -2
-6 2
-5 0
-4 2
-3 4
-2 6
-1 3
0 1
1 -1
2 -3
3 0
4 2
72 changes: 72 additions & 0 deletions Tests/Task1/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from utilities import ReadSignal
def check_signal(signal3 ,Expected ,Message):
Your_indices,Your_samples = signal3.get_signal_indexs(),signal3.get_signal_values()
expected_indices,expected_samples=Expected.get_signal_indexs(),Expected.get_signal_values()
if (len(expected_samples)!=len(Your_samples)) and (len(expected_indices)!=len(Your_indices)):
return Message+" Test case failed, your signal have different length from the expected one"

for i in range(len(Your_indices)):
if(Your_indices[i]!=expected_indices[i]):
return Message + " Test case failed, your signal have different indicies from the expected one"
for i in range(len(expected_samples)):
if abs(Your_samples[i] - expected_samples[i]) < 0.01:
continue
else:
return Message +" Test case failed, your signal have different values from the expected one"

return Message +" Test case passed successfully"

class Task1Test:
def AddationTest (self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
signal2 = ReadSignal("Tests/Task1/Signal2.txt")
signal3 = signal1 + signal2
addSignal = ReadSignal("Tests/Task1/add.txt")
print(check_signal(signal3,addSignal,"Addation"))

def SubtractiaonTest (self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
signal2 = ReadSignal("Tests/Task1/Signal2.txt")
signal3 = signal1 - signal2
SubSignal = ReadSignal("Tests/Task1/subtract.txt")
result = check_signal(signal3 , SubSignal , "Subtraction")
print(result)

def MulTest(self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
signal3 = signal1 * 5
mulBy5Signal = ReadSignal("Tests/Task1/mul5.txt")
result = check_signal(signal3 , mulBy5Signal , "Mul5")
print(result)

def AdavnceTest(self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
advance5 = ReadSignal("Tests/Task1/advance3.txt")
signal1.DelayingOrAdvancingSignalByK(-3)
result = check_signal(signal1,advance5,"Advacning By 5 ")
print(result)

def DelayTest(self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
delay5 = ReadSignal("Tests/Task1/delay3.txt")
signal1.DelayingOrAdvancingSignalByK(3)
result = check_signal(signal1,delay5,"Delay By 5 ")
print(result)

def FoldingTest(self):
signal1 = ReadSignal("Tests/Task1/Signal1.txt")
mirror = ReadSignal("Tests/Task1/folding.txt")
signal1.mirror()
result = check_signal(signal1,mirror,"Folding")
print(result)

def Task1TestRunner(self):
print("Run Task 1 Tests ")
print(".......................")
self.AddationTest()
self.SubtractiaonTest()
self.MulTest()
self.AdavnceTest()
self.DelayTest()
self.FoldingTest()
print("*"*50)
15 changes: 15 additions & 0 deletions Tests/Task1/delay3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
0
0
12
-1 -2
0 2
1 0
2 2
3 4
4 6
5 3
6 1
7 -1
8 -3
9 0
10 2
Loading