diff --git a/python_symb/__pycache__/expr.cpython-311.pyc b/python_symb/__pycache__/expr.cpython-311.pyc deleted file mode 100644 index a46f047..0000000 Binary files a/python_symb/__pycache__/expr.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/fraction.cpython-311.pyc b/python_symb/__pycache__/fraction.cpython-311.pyc deleted file mode 100644 index 07a9c8a..0000000 Binary files a/python_symb/__pycache__/fraction.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/operator_file.cpython-311.pyc b/python_symb/__pycache__/operator_file.cpython-311.pyc deleted file mode 100644 index 59cbcc9..0000000 Binary files a/python_symb/__pycache__/operator_file.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/parse.cpython-311.pyc b/python_symb/__pycache__/parse.cpython-311.pyc deleted file mode 100644 index bce1ac4..0000000 Binary files a/python_symb/__pycache__/parse.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/symbols.cpython-311.pyc b/python_symb/__pycache__/symbols.cpython-311.pyc deleted file mode 100644 index 60a6d73..0000000 Binary files a/python_symb/__pycache__/symbols.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/tools.cpython-311.pyc b/python_symb/__pycache__/tools.cpython-311.pyc deleted file mode 100644 index 9c4ba3f..0000000 Binary files a/python_symb/__pycache__/tools.cpython-311.pyc and /dev/null differ diff --git a/python_symb/__pycache__/tree.cpython-311.pyc b/python_symb/__pycache__/tree.cpython-311.pyc deleted file mode 100644 index 64d3f43..0000000 Binary files a/python_symb/__pycache__/tree.cpython-311.pyc and /dev/null differ diff --git a/python_symb/expr.py b/python_symb/expr.py deleted file mode 100644 index a8b2c4f..0000000 --- a/python_symb/expr.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import annotations -from tree import Tree -from operator_file import Add, Mul -from operator_file import UnaryOperator, BinOperator -from typing import List -from symbols import Var -from parse import infix_str_to_postfix - - -class Expr(Tree): - def __init__(self, value, children=None): - super().__init__(value, children if children else []) - - @staticmethod - def from_postfix_list(postfix: List): - - def aux(): - first = postfix.pop() - match first: - case int() | Var(): - return Tree(first) - case UnaryOperator(): - return Tree(first, [aux()]) - case BinOperator(): - return Tree(first, [aux(), aux()]) - - return aux() - - @staticmethod - def from_infix_str(expr_str): - expr_rev_polish = infix_str_to_postfix(expr_str) - return Expr.from_postfix_list(expr_rev_polish) - - - - - - diff --git a/python_symb/fraction.py b/python_symb/fraction.py deleted file mode 100644 index 8f09354..0000000 --- a/python_symb/fraction.py +++ /dev/null @@ -1,131 +0,0 @@ -from __future__ import annotations -from typing import Iterable, Generator -from tools import gcd - - -class Fraction: - """ - Should represent a fraction not a division - """ - __slots__ = ['num', 'den'] - __match_args__ = ("num", "den") - - #todo check if num and den are part of a domain, so a/b as a meaning a gcd work well - #todo implement __iadd__ etc... if performance needed - - def __init__(self, *args): - match args: - case num, den: - self.num = num - self.den = den - case x, : - self.num = x - self.den = 1 - - def __repr__(self): - return f'Fractions({self.num}, {self.den})' - - def simplify_gcd(self): - """Simplify fraction by diving num and den by their gcd - return None""" - match self.num, self.den: - case int(num), int(den): - gcd_ = gcd(num, den) - self.num //= gcd_ - self.den //= gcd_ - # can be completed with others objects that support gcd like polynomials etc... - - def simplify_to_num(self): - """from frac(a, 1) return a.""" - if self.den == 1: - return self.num - def simplify_nested(self, rec=True): - """simplify nested fractions. - Fractions(1, Fractions(1, Fractions(1, Fractions(1, 2)))) -> Fractions(2, 1) - For one simplification step put rec=False - - return None""" - - def aux(fract): - match fract: - case Fraction(Fraction(a, b), Fraction(c, d)): - fract.num = a * d - fract.den = b * c - case Fraction(num, Fraction(a, b)): - fract.num = num * b - fract.den = a - case Fraction(Fraction(a, b), den): - fract.num = a - fract.den = b * den - - if rec: - num, den = self.num, self.den - if isinstance(num, Fraction) or isinstance(den, Fraction): - aux(fract) - - aux(self) - - def simplify_all_(self): - self.simplify_gcd() - self.simplify_nested() - res = self.simplify_to_num() - if res: - return res - - return self - - def __add__(self, other): - match other: - case int(x): - return Fraction(self.num + self.den * x, self.den) - case Fraction(num, den): - result = Fraction(self.num * den + num * self.den, self.den * den) - return result - return ValueError - - def __radd__(self, other): - return other + self - - def __neg__(self): - return Fraction(-self.num, self.den) - - def __mul__(self, other): - match other: - case int(x): - return Fraction(self.num * x, self.den) - case Fraction(num, den): - result = Fraction(self.num * num, self.den * den) - return result - return ValueError - - def __rmul__(self, other): - return self*other - - def __truediv__(self, other): - match other: - case int(x): - return Fraction(self.num, self.den * x) - case Fraction(num, den): - return Fraction(self.num * den, self.den * num) - - def __rtruediv__(self, other): - res = self/other - return Fraction(res.den, res.num) - - -if __name__ == "__main__": - a = Fraction(1, 2) - a += 1 - print(a) - - - - - - - - - - - - diff --git a/python_symb/integers.py b/python_symb/integers.py deleted file mode 100644 index cc56d3b..0000000 --- a/python_symb/integers.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Python int is already an arbitrary precision integer, so we don't need to implement it. -""" diff --git a/python_symb/operator_file.py b/python_symb/operator_file.py deleted file mode 100644 index 1c935e9..0000000 --- a/python_symb/operator_file.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import annotations -from typing import Dict, Callable -from symbols import Symbols - - -class Operator(Symbols): - instances = [] - def __init__(self, name : str, precedence: int, call: Callable): - super().__init__(name) - self.precedence = precedence - self.call = call - Operator.instances.append(self) - - def __repr__(self): - return f'{self.name}' - - -class UnaryOperator(Operator): - instances = [] - - def __init__(self, name: str, precedence: int, call: Callable): - UnaryOperator.instances.append(self) - super().__init__(name, precedence, call) - - def __call__(self, expr): - return self.call(expr) - - -class BinProperties: - - def __init__(self, associativity: bool, commutativity: True, - left_distributivity: Dict[str, bool], right_distributivity: Dict[str, bool]): - - self.associativity = associativity - self.commutativity = commutativity - self.left_distributivity = left_distributivity - self.right_distributivity = right_distributivity - - -class BinOperator(Operator): - instances = [] - - def __init__(self, name: str, precedence: int, properties: BinProperties, call: Callable): - BinOperator.instances.append(self) - super().__init__(name, precedence, call) - self.properties = properties - - def __call__(self, left, right): - return self.call(left, right) - - -AddProperties = BinProperties(True, True, {'*': True}, {'*': True}) -Add = BinOperator('+', 2, AddProperties, lambda x, y: x + y) - - -MulProperties = BinProperties(True, True, {'+': True}, {'+': True}) -Mul = BinOperator('*', 3, MulProperties, lambda x, y: x * y) -Sin = UnaryOperator('sin', 0, lambda x: x) - -Min = BinOperator('-', 1, AddProperties, lambda x, y: x - y) -# Pns = UnaryOperator('()', 0, lambda x: x) - diff --git a/python_symb/parse.py b/python_symb/parse.py deleted file mode 100644 index da16714..0000000 --- a/python_symb/parse.py +++ /dev/null @@ -1,114 +0,0 @@ -from __future__ import annotations -from typing import List, Union -from operator_file import Add, Mul, Min, BinOperator, UnaryOperator -from symbols import Symbols, Var -from fraction import Fraction - -x, y = Var('x'), Var('y') - -ParenthesisLeft = Symbols('(') -ParenthesisRight = Symbols(')') - -Number = Union[int, float, Fraction] - -name_to_symbol = {sy.name:sy for sy in Symbols.instances} - -print(name_to_symbol) - -""" -example1 = "a + b * c + d" -- -example2 = 2*x+3*y*(4+sin(5)) -- -example3 = "(a + b) * (c + -d))" -should return Tree(Expr('*', [Expr('+', [Expr('a'), Expr('b')]), Expr('+', [Expr('c'), Expr('-', [Expr('d')])])])) -""" - - -def preprocess(expr: str) -> List: - """ - Preprocesses a string expression to a list of symbols and numbers - :param expr: string expression - :return: list of symbols and numbers - """ - return_list = [] - expr = expr.strip() - expr = expr.replace(' ', '') - m = max([len(sy) for sy in name_to_symbol.keys()]) - i = 0 - while i < len(expr): - found = False - for j in range(m, 0, -1): - word = expr[i:i+j] - if word in name_to_symbol or word.isdigit(): - if word in name_to_symbol: - return_list.append(name_to_symbol[word]) - else: - return_list.append(int(word)) - i += j - found = True - break - - if not found: - raise ValueError(f'Invalid expression: {expr} at index {i}\n') - return return_list - - -def return_to_string(expr: List) -> str: - """ - Returns a string expression from a list of symbols and numbers - :param expr: list of symbols and numbers - :return: string expression - """ - return ' '.join([str(sy) for sy in expr]) - - -def infix_to_postfix(expr: List) -> List: - global ParenthesisLeft, ParenthesisRight - """ - Converts an infix string expression (standard) to a postfix expression (reverse polish notation) - :param expr: infix expression - :return: postfix expression - - use shunting yard algorithm - """ - op_stack = [] - postfix = [] - for sy in expr: - match sy: - case int() | float() | Fraction() | Var(): - postfix.append(sy) - case _ if sy == ParenthesisLeft: - op_stack.append(sy) - case _ if sy == ParenthesisRight: - while op_stack[-1] != ParenthesisLeft: - postfix.append(op_stack.pop()) - op_stack.pop() - case UnaryOperator(): - op_stack.append(sy) - case BinOperator(): - while op_stack and op_stack[-1] != ParenthesisLeft and op_stack[-1].precedence >= sy.precedence: - postfix.append(op_stack.pop()) - op_stack.append(sy) - while op_stack: - postfix.append(op_stack.pop()) - return postfix - - -def infix_str_to_postfix(expr): - return infix_to_postfix(preprocess(expr)) - - -if __name__ == "__main__": - - expr = "(x+7)*y+sin(24-2*(1-5))" - prep = preprocess(expr) - print(prep) - post = infix_to_postfix(prep) - print(post) - print(return_to_string(post)) - - - - - diff --git a/python_symb/symbols.py b/python_symb/symbols.py deleted file mode 100644 index f853677..0000000 --- a/python_symb/symbols.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations - - -class Symbols: - """ - All maths things (other than number) that will be parsed need to be of "Symbols" class - """ - instances = [] - - def __init__(self, name): - self.name = name - Symbols.instances.append(self) - - def __repr__(self): - return self.name - - def __str__(self): - return self.name - - -class Var(Symbols): - """ - variable, like 'x' in x+2 - """ - instances = [] - - def __init__(self, name): - super().__init__(name) - print(self.__class__) - self.__class__.instances.append(self) - diff --git a/python_symb/tools.py b/python_symb/tools.py deleted file mode 100644 index 3d3b00a..0000000 --- a/python_symb/tools.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations -from typing import * - - -def gcd(a, b): - - if b > a: - return gcd(b, a) - - if b == 0: - return a - - return gcd(b, a % b) - diff --git a/python_symb/tree.py b/python_symb/tree.py deleted file mode 100644 index ec1a252..0000000 --- a/python_symb/tree.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations -from typing import Iterable, Generator -from collections import deque - - -class Tree: - """ - Ultra generic Test class. Can be used to represent any Test structure. - - value : value of the node. Can be a binary operator like "+", a ternary operator like "if", a number etc... - - depth_first_order : the default order of the node in the depth first traversal. Used to implement the depth_first method. - 0 is pre-order, 1 is in-order (for binary Test), -1 is post-order. - for instance to write "a ? b : c" you need to write Tree("?", [Tree("a"), Tree("b"), Tree("c")]) - and set the depth_first_order of the "?" node to 1. - - children : the children of the node. Can be empty. - """ - __slots__ = ['value', 'children', 'depth_first_order'] - - def __init__(self, value, children: Iterable[Tree] = None, depth_first_order: int = 0): - self.value = value - self.depth_first_order = depth_first_order - self.children = children if children else [] - - def __repr__(self) -> str: - return f'Tree({self.value}, {self.children})' if self.children else f'Leaf({self.value})' - - def height(self) -> int: - return 1 + max((child.height() for child in self.children), default=0) - - def size(self) -> int: - return 1 + sum(child.size() for child in self.children) - - def breadth_first(self) -> Generator[Tree]: - - queue = deque([self]) - - while queue: - poped = queue.popleft() - for child in poped.children: - queue.append(child) - - yield poped - - def depth_first_default(self) -> Generator[Tree]: - - def aux(tree): - n = len(tree.children) - if not tree.children: - yield tree - - for i, child in enumerate(tree.children): - if i == tree.depth_first_order: - yield tree - - yield from aux(child) - - if tree.depth_first_order == -1: - yield tree - - yield from aux(self) - - def depth_first_pre_order(self) -> Generator[Tree]: - - def aux(tree): - yield tree - for child in tree.children: - yield from aux(child) - - yield from aux(self) - - def depth_first_post_order(self) -> Generator[Tree]: - - def aux(tree): - for child in tree.children: - yield from aux(child) - yield tree - - yield from aux(self) \ No newline at end of file diff --git a/python_symb/visual.py b/python_symb/visual.py deleted file mode 100644 index 758d02a..0000000 --- a/python_symb/visual.py +++ /dev/null @@ -1,92 +0,0 @@ -import tkinter as tk -from expr import Expr - -class Visual: - def __init__(self): - self.root = tk.Tk() - self.root.title("Visual") - self.root.geometry("800x800") - - # Add a canvas on the left side of the window - self.tree_canvas = tk.Canvas(self.root, width=500, height=500, bg="white") - self.tree_canvas.pack(side=tk.LEFT, expand=False) - - # Create right frame - self.right_frame = tk.Frame(self.root, width=300, height=500, background="grey") - - - # Add a label with the text "Input" on top of the right frame, should not take all the space - self.input_label = tk.Label(self.right_frame, text="Input (infix string):") - - - # Add a entry below the label with default text "(5+2)*3" - self.input_entry = tk.Entry(self.right_frame, width=50) - self.input_entry.insert(0, "(5+2)*3") - - - - # Add a button below the entry with the text "To Tree" - self.input_button = tk.Button(self.right_frame, text="To Tree", command=self.show_tree) - - # Pack the widgets, make sure they are not expanding, and all are fixed size - - - self.input_label.pack() - self.input_entry.pack() - self.input_button.pack() - self.right_frame.pack(side=tk.LEFT, expand=False) - - - - - - - self.root.mainloop() - - def show_tree(self): - # Get the text from the entry - text = self.input_entry.get() - - # Clear the canvas - self.tree_canvas.delete("all") - tree = Expr.from_infix_str(text) - - # Draw the tree - self.draw_tree(tree) - - def create_circle(self, x, y, r, color): # center coordinates, radius - x0 = x - r - y0 = y - r - x1 = x + r - y1 = y + r - return self.tree_canvas.create_oval(x0, y0, x1, y1, fill=color) - - def draw_tree(self, tree, first_x=250, first_y=50, x_offset=100, y_offset=100): - - children = tree.children - n = len(children) - for i in range(n): - child = children[i] - x = first_x + (i - (n - 1) / 2) * x_offset - y = first_y + y_offset - - #Link the node to the parent - self.tree_canvas.create_line(first_x, first_y, x, y) - # Draw the node - self.draw_tree(child, int(x), y, x_offset, y_offset) - - # Draw the root node - self.create_circle(first_x, first_y, 20, "red") - self.tree_canvas.create_text(first_x, first_y, text=str(tree.value)) - -if __name__ == "__main__": - Visual() - - - - - - - - -