Delete python_symb directory

This commit is contained in:
Crizomb 2023-08-02 04:13:22 +02:00 committed by GitHub
parent 7e1ff3b6b2
commit 299fc1a058
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 0 additions and 565 deletions

View file

@ -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)

View file

@ -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)

View file

@ -1,3 +0,0 @@
"""
Python int is already an arbitrary precision integer, so we don't need to implement it.
"""

View file

@ -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)

View file

@ -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))

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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()