Refactor code in directories + add doc strings

This commit is contained in:
Clément Barthélemy 2024-02-20 00:01:25 +01:00
parent 1e5113b208
commit 0d9a636da6
8 changed files with 175 additions and 81 deletions

View file

@ -0,0 +1,131 @@
from __future__ import annotations
from typing import Iterable, Generator
from python_symb.IndependantTools.tools import gcd
class Fraction:
"""
Represent a fraction a/b with a and b elements of a ring (support +, -, *, /)
"""
__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

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

View file

@ -0,0 +1,105 @@
from __future__ import annotations
from typing import Dict, Callable
from python_symb.MathTypes.symbols import Symbols
class Operator(Symbols):
"""
Represent an operator, like +, *, sin, anything that can be applied to an expression
"""
instances = []
def __init__(self, name: str, precedence: int, call: Callable):
"""
:param name of the operator
:param precedence: precedence of the operator, higher is better
:param call: function to apply the operator
"""
super().__init__(name)
self.precedence = precedence
self.call = call
Operator.instances.append(self)
def __repr__(self):
return f'{self.name}'
class UnaryOperator(Operator):
"""
Represent a unary operator, like sin, cos, - etc...
all operators that take only one argument
"""
instances = []
def __init__(self, name: str, precedence: int, call: Callable):
UnaryOperator.instances.append(self)
super().__init__(name, precedence, call)
def apply(self, expr):
return self.call(expr)
def __call__(self, e):
from python_symb.Expressions.expr import Expr
return Expr(self, [e])
class BinProperties:
"""
Represent the properties of a binary operator
"""
def __init__(self, associativity: bool, commutativity: True,
left_distributivity: Dict[str, bool], right_distributivity: Dict[str, bool]):
"""
:param associativity: True if the operator is associative
:param commutativity: True if the operator is commutative
:param left_distributivity: a dictionary of the operators that the current operator distribute over
:param right_distributivity: a dictionary of the operators that distribute over the current operator
exemple:
for the operator *:
associativity = True
commutativity = True
left_distributivity = {'+': True}
right_distributivity = {'+': True}
"""
self.associativity = associativity
self.commutativity = commutativity
self.left_distributivity = left_distributivity
self.right_distributivity = right_distributivity
class BinOperator(Operator):
"""
Represent a binary operator, like +, *, etc...
all operators that take two arguments
"""
# Used to store all the instances of BinOperator, used in the parser
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 apply(self, left, right):
return self.call(left, right)
"""
Generic operators
"""
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', 10, lambda x: x)
Min = BinOperator('-', 2, AddProperties, lambda x, y: x - y)