Refactor code in directories + add doc strings
This commit is contained in:
parent
1e5113b208
commit
0d9a636da6
8 changed files with 175 additions and 81 deletions
131
python_symb/MathTypes/fraction.py
Normal file
131
python_symb/MathTypes/fraction.py
Normal 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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
3
python_symb/MathTypes/integers.py
Normal file
3
python_symb/MathTypes/integers.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Python int is already an arbitrary precision integer, so we don't need to implement it.
|
||||
"""
|
105
python_symb/MathTypes/operator_file.py
Normal file
105
python_symb/MathTypes/operator_file.py
Normal 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)
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue