From 1e5113b2088ff41b05b79fa5f437c2a27de75383 Mon Sep 17 00:00:00 2001 From: Crizomb <62544756+Crizomb@users.noreply.github.com> Date: Wed, 2 Aug 2023 04:15:58 +0200 Subject: [PATCH] Add files via upload --- python_symb/__pycache__/expr.cpython-311.pyc | Bin 0 -> 3941 bytes .../__pycache__/fraction.cpython-311.pyc | Bin 0 -> 6417 bytes .../__pycache__/operator_file.cpython-311.pyc | Bin 0 -> 4547 bytes python_symb/__pycache__/parse.cpython-311.pyc | Bin 0 -> 5957 bytes .../__pycache__/symbols.cpython-311.pyc | Bin 0 -> 1844 bytes .../symbols_and_expr.cpython-311.pyc | Bin 0 -> 5656 bytes python_symb/__pycache__/tools.cpython-311.pyc | Bin 0 -> 550 bytes python_symb/__pycache__/tree.cpython-311.pyc | Bin 0 -> 5383 bytes python_symb/expr.py | 63 +++++++++ python_symb/fraction.py | 131 ++++++++++++++++++ python_symb/integers.py | 3 + python_symb/operator_file.py | 62 +++++++++ python_symb/parse.py | 121 ++++++++++++++++ python_symb/symbols.py | 34 +++++ python_symb/tools.py | 14 ++ python_symb/tree.py | 81 +++++++++++ python_symb/visual.py | 123 ++++++++++++++++ 17 files changed, 632 insertions(+) create mode 100644 python_symb/__pycache__/expr.cpython-311.pyc create mode 100644 python_symb/__pycache__/fraction.cpython-311.pyc create mode 100644 python_symb/__pycache__/operator_file.cpython-311.pyc create mode 100644 python_symb/__pycache__/parse.cpython-311.pyc create mode 100644 python_symb/__pycache__/symbols.cpython-311.pyc create mode 100644 python_symb/__pycache__/symbols_and_expr.cpython-311.pyc create mode 100644 python_symb/__pycache__/tools.cpython-311.pyc create mode 100644 python_symb/__pycache__/tree.cpython-311.pyc create mode 100644 python_symb/expr.py create mode 100644 python_symb/fraction.py create mode 100644 python_symb/integers.py create mode 100644 python_symb/operator_file.py create mode 100644 python_symb/parse.py create mode 100644 python_symb/symbols.py create mode 100644 python_symb/tools.py create mode 100644 python_symb/tree.py create mode 100644 python_symb/visual.py diff --git a/python_symb/__pycache__/expr.cpython-311.pyc b/python_symb/__pycache__/expr.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e6e0e8b86c3d73afeca245b4973f990358d52ae GIT binary patch literal 3941 zcmcgvO>7&-6`tAUl1quyKSkSe8(NNyFb>3~Q57R{jONE^3)iXvMTWhIv8A~yi|zg} zv&&RcltKjrm@a&fiU^XC7+`?fmEatTUfN@i36KISLx70|1QZBz=#7DT2y*Isvn0h8 zm7te)X8302&CJ`G@6CJj_@`vDi$Hqu@n_o0Q9{1JPBTeCgYJI{jSZp^jT*$H3Z>W< z48ar?k+(%7VoHi+MwKY+K~nnkey!`*0`}N(f#^xC`w@j1@Cy>>CBnRdpbRL3T5_7; zFWd7koSLP6ciysWH}4j0%Ykm>EvD;P!53fCG+(?@HnNhRoU!t3;TI*Hed*o2QPzFAFjq7*rdxhoRSQPm zaa7g8y=5|)(M=4?~X6%5_fEjM>{p)i+c=2d3@N-wxhuC(CJ*;b>Q)ADW}p)VKQ z#)#@Hn748|oPDgczy?6-ViJ)UYwo5SSk4PTzFsDKa`JBMUhJuS?1_AAGqv?oFLR+P zSLMHr?#Qq1%CCCOvJdl#A8Tlrp)D2K5ked|vS*=jhui^dD-@I~XmmyXJr&4Z8df2w zNSG?X(5CJ0^^HppF}+8S(cgay4%mO$t8)NQGPfc6Xg4iI_T|k(@V_tBYj#%$KRm>dhdp-3-m#a<-i9@+al$Z+Au}c1I?>p$S}Z z8Yi=3ux)k{NLJtw@KZZ@qkj2g4ujv{arnjIqe1C`RZb4b*8oI4D#u^0lW!wKq;Ig| z+%4ZLR}y>^A)`V)aHB$Z6?RsK@8|oW`(JId1z6fhOZ4!aW_>V}6od17p9e&@vb-4o|4 zy?ecbPkYZi={-}mcX}swdnY`3B7gvo-As5zIRwvxQ`i9i3uf3HgSufjDKs1~sWy+a zBrL(~qfFyFT*ayHbQOUkK{wS%M>vv9=Pp9KI;4Wm{l$qJZ_0=B2}|@tqKPhAZX+F5 zxyJnoR5JYe}TomxnFmAhZ@Vp6jDex4{+c0peXsLEdEkK;XUnH9?rumKN z92f;b&YyvRujm=9^{3Z|R)>SU2K8QgWb^gvP_!W7+CATv48dtuMe)K zg1pA-&D4Xz%~X)@^SYXTn5w3O{BfhkUPJ0bck9x}@BQ&TFZ0q)dVDuM?)8n=`Um#X zr@YbYe@_8{@{e)v>da@8pHBweo%D^}^bN1?MsP*j?F;=WzoHkQ0auh%q3%peAqx$A z>>zjutWjY2HuI=!Ti}4R=YbKjyO^rxHBD6)6CB<~?;K3qM-2j|a^k7{%o7>h=tE~m zKDR5M^P1)VbpkXLHg?3;&9c$9b>72i><38D6BqvX@S=?!xjCnNt8H_<_hM*sO)cR| z$>X4G0wX;uZ|bV*cd4prYh?r52~~ZkoHv3I9*Ox02jlR9sY48>ac9fUpd7Apd^6Y& zk&FZJla1K0pc{Z!ma<{sI_TnpCn+#n^x7CnIDZ8K4^A`J1u9*vlW!wY5*?@u2`N=4 zP4blpyp^{D?nyo_Nbq(6X$>Jmj!6owlQud)r5Es14H9j&IPXyRU|y@mmClcYNSb+Y zBdSm5eY!A}9YRQF%Wjzgqzs=1a7OS4hKDhJGVo?LQ)i2Ye(+c2AiiO!X+H}7t7zTk z`toBKA=`$-!y#WP<(Z?mJ%K-h1#A)t8Z>vK!3HrL`bNGG==UOf1G=aU2WefTl-9_o z7cMoD^1`KaPOzj#-thjrQX^?ET#n+L^+>4Hqt8*$PbaC2e}&wC9}HciB$B8sJ`s<5 r;_+H{Pvs>DQO@5xzdF4-y*apc{e$bvZ!W*K{0?St%8?T=jU)6Q$g*bM literal 0 HcmV?d00001 diff --git a/python_symb/__pycache__/fraction.cpython-311.pyc b/python_symb/__pycache__/fraction.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07a9c8a38ea9b1faccdfe68defbf9236a6bda5e1 GIT binary patch literal 6417 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 literal 0 HcmV?d00001 diff --git a/python_symb/__pycache__/operator_file.cpython-311.pyc b/python_symb/__pycache__/operator_file.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfd48b6a22025edbfa7f74cbbb9ef7366bad277c GIT binary patch literal 4547 zcmc&1O>Y~=b%wiK4k^);ELl;UT9zEiHYM3|J{r`C;e0s#I>b$3^}?c9taexSy33Eu zE*sM(8XgQ(E(}D61SZmp4uxvL7x(7B&>LwGFtI>@0zLW0KsgjT^}X5Ua!HB`kV}WV zZ)fJs%zN{``HyruMWDU;tVYIVmsa zWHFZPcwWgVl*Gs{i6P%7M%+|(B|@IS>$hA&;1s|m%)|hW2^<4layJIM;0<;q1ttZU zv7ue57%`K^IQ-JaxJ7-qE5m+xgZ*Q$CS@EmGUk{uai0ue$HNnji4z1ISd$hfq>V{4 zZ5$su;TT|ZV~9beOOTt|#lj0FT4rdMHyE zAX#|n{@*Gy zW<=Xjy1nSPN(N6h$PKbbuV)ip+$qDQJ*KKw!E#lVkHJo!Mt~H&q*ZWS4KD9^idHI_ z1!FJn$&P7n@+2+_mwQQ7)osmjRMkO#=AqRN*4J(o^X8gvn|ZU~u6RCtt9I=WJnTvB}Q0 z*ttgc*@u&e9_j-I*cUoJ4xLA&N^Zl~Z+`=c@(lE|R0sw>Ct&2@mU;dPK$I~zOI%g^ zSof!n;o5NkHPSvl^Hp~1&kc5p&%(r>;tLw%k}qvs=4%M$3_65^(Oy;6OQ~wUXq0X2 zkE`luWzF_6961(p<0ql#r2}Q@rfsY09_2GIE13O2Fe{WV09usuTL2)`?yo&@y!Pu( zOpc%LkWpZq#^*ZZC?KvUXy|Z!*a8#(5&oP0T|wiOu2~!{wm#oQISRc#gpTmtkQ+j7 zhZe9C`eFnPRxs#YZjdQ()qv+mBSv^gm4c^B{gD!LNY|p`{0yx1RXByc2?Xc_d>TN{ z-F(#v@0jV6Md%{JCa=II;UXtm?DPwE_BlJd<2Ko9i>)@;>VW6e?>>IJ$u70nrAGG= ziqoUQK%EHzu0jVLV+X#&Z7{?I7XjSd+F7>%DsM;Hx!7LkSyZ`e=*(C9w;W-pByDM(y0rZPxcV_y0r3j-*GNY{cO zorVZp)GbJwf3n<)CvOyswwKn6`Ft5OsXw{S%ceJFo13m`SP*cnjk1qA$Y75BJxs06 zL)7-jwYjBy44%2POrqKOW=z#7iq^T~>Php`0i4+!Gi;$`uO=vxHm-!0p=NAyH zA$S8oHZF|gFjQ#&zP0$-VWv+kq5Y$Z9V`rLq@$3zl`R?KfBV$3|9$-({LZ%*e}>WIzBkMdv(#Ze#_vWF>yN zLq-7q5ZvEqDj9UE}ik7PSEyK%W(aA@m!- z{GURoJQzZSy@j^gvoMAK6u3MzpuPi$tm4~RufV}sKjn%%i8&GLoB3KK;!Z~-8QL3K zvhyJT5pSnj?9>ak_?#{7tT)+mi!C?U@=@_Ns8+TzTN$BwJy0|pNC@T<;dp3?M+Mz# ztp6WG5O( z>dS9ojKkUsMO~$Lq1P4UThQN&dGwA)E78Ptz^>R@e#6kN@{eE%lGsN<)W}oq*}^}~ znjaKiqP%~Q9@ue|9)BM;MTrR#0$c_RzlHz{NcbCL6<#9Q!)sYIX1r4LaHw8Cfayr} z+B^MSMBt_xc{~~1;DBEELH>b*D2XHZ$NHql|Ml!7*0q~ux6GlgVu7?2p>lR;FtC?Vs1* Ztlz8OYbq-(Wu+$ldlZ$LRFj0N{s)O_i~j%s literal 0 HcmV?d00001 diff --git a/python_symb/__pycache__/parse.cpython-311.pyc b/python_symb/__pycache__/parse.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a587c6221d5094195fe60762c7fa6e665529584 GIT binary patch literal 5957 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 literal 0 HcmV?d00001 diff --git a/python_symb/__pycache__/tools.cpython-311.pyc b/python_symb/__pycache__/tools.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c4ba3f815ff93d4e58f13075ce1d2b5ac2df411 GIT binary patch literal 550 zcmZWmze~eF6n-yhYphg79O_mDhd3A<1r^+-6zXD^aOP60Cb@dK2$2p&94a`}sk4hB z;=keCu>=G`9NY@sI(gStL4CaY-uvFY?|weya#@geckn`=WqeoU+q7|lgMv&tK!KtM zK2{J_u6f!%Q2h!jI!%?qOn<6&6O$Pd1WXWd%z{u-TyrK1sd-4tp#$K6%A^AgY`|$s zP4IbvDvnLn@1^ePM_ZP?6i-K-YYiyF-~I+(WZ<95)QVh*gPMYdN0lyMeGuu~Q@5FL8F_IwG{{v8b_NLM=)Ju|vTlM_3N=9J|W6?|PPC%nR4+ zF_-(p2-G#hO$kkSn=)D(mr*l%om*&cw8?dR6L*cgD(_yNH_v->^DX0JX0~?QSYRkYXsBsU&OL)ks9#wQVk64w8(B>&L;-XrD*m>I3<-grTwJGa7mB4xg1& fy=J&2p|2xi4_3Ory$6fkZ|`ReT7&-6`tkpQlunGw5VTORyVZen6*O1wGGs=W5texH2#qTL@o+8F0tZ{Bs$9_ zGrLSJmIizYP=+eG7L$0|J z?IHnMptH+2|8M4f?`LND+eoC7K$@-m$@oK6VpubSIm)>_or~z3Wh>&zaN>ze6o3I(Y`8RD*t0q)>%WmYbm7|{l(n4!HXWvG3%KoUMw_L!qh(Cp zwv*ahx~0ugt!Pt2bMhLa1x9UZIht-QiGjAmiW#TKXtI;@`dBxMRGZR7o}bs8MXFhO zgL=$#Z7yr+Y)Q)(1WcNl{g7($L-7es*8s(Ko!NQbYZY^Ilxft-B$JH=4O(y()ALzo zJLx<#pm&O|Y0!DSXgZo`YuSjFwHgCpqQ)m`Apggd*}9q3E;nS&<_adwp{yuD%PLxq zI*WND$;EwL%i0=%@)}=eLOYE0tR<@2!TCIEN{g^2CbZZ1h(g|W#2CQ_$7LE z4tW}=H4p-ZTwS<}!wrZti&@iP)M_B>Ra-#yv`cdZXGsW^kX@CVfg5U0ad))=2@Jz(R42jR^|Wx0Mh|!XNeA?nEG)U9bUJHgopibsL8T>|)j?Rz z9tU!R)CP7hE4MmpuY7A+*$j=<_D@uYkFJH*LXYFn9$ALx84M(DkWuhK%avihj3+(x zsPN-hU4Q~$MXo|F5{nst+*NP%FCogb_CsC%Otm@XR)Lh_`U&*-LoD(Urq17_LZ z1oAg{ZjkEG8F(KaTT_44{fq8Td+zp#mR8Ea1ae#IOyb@eod%&1ere9EgOS+ zsjFop*kB(50!rCz~N2?w;%7LI7u*5Gt?aQdNIDXy08 zlx~+-%23_*a@bHib}`ppJFnuhVQ<-2aE${%n!4dEANPO07dUSWPHzH@O>f4gH+rY5 zp=r*4tJk~Qhyd+FPyuH9&;#y6L3lu`x0T6)rA_+@mU;#B5uM^+-s z>XV*Wov7jATK~xE#XA>oUs}1e{B~_*?Cw~dNRj=VRMc8@V72>B_uA!+=)TS9zAAs8 z^bIYa$EV&!diyz-c4VhlA#z+>c!>T)68c(}<|RYA8Ty$NAU}n}!H?tHfZC5_z%lS+ zet(8Y7?{~%0z3#l0j8fcnEH+2dARj62V-an#WtKdLSYV`V2#u|!ao}fVjQot*8^Y{ zc#3(3@gX-F=J5l;lYTlI2QSZaJ>37q8hU6`Ictek?LnLTQ{^P3r}z5p|!32$*^phT6XY@=sw& ze~HE_XICz6MB|&$`10vmY-r^Tw3t1$!QGWke7+nVzh~UfZHyk>96eemO5^}1w?h@F za;z5XUsE=RlV8M=)mXB&d#rK}pC^09){d+dKb^WeRgI3feV_EkHhae(_I=TNsM>qT zTMbvN%OpAhjoj?k$$Egh5tmXNU~h`sK&*|hrQsLBFo}}mLEezOu5^d@)JYpMO8SQ? zM=H+k<15Fjq0tw;|7))}2YYXNMbnzV)}U1+u;SQtbiF`%Td3S-q5WR?f-4r@Q`cp7 z3^HzD0%mjozj?j716TNN5qEH(fxQJY?HM2qm}`B5%jfW^jqJU<7flQ72M9!@|7;|6 zxjCGJ&5q+Pr*H-IORZrC1Fd%8?W(l<#XCNYEPS>ghhbZ7Naz29EqomtXj+hG3kb71+pJk`ZBJl(1ix-9Jx9}Nw=)@2Lm6)KHxu878|BHVW-; z^7d^s7*>bt#7_pJDg+Kc+24U}e$wZ!`g?^Pp|~@NP6T+qi2pkQd}!@%&{-;Etp$b` zGls{j+m*?iCVZIVKXl@frxtW(Q-*MH+_nL_6*?)Dc8XnuA$Tpde+~qKm?YImyy|~z k 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 new file mode 100644 index 0000000..cc56d3b --- /dev/null +++ b/python_symb/integers.py @@ -0,0 +1,3 @@ +""" +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 new file mode 100644 index 0000000..f04be55 --- /dev/null +++ b/python_symb/operator_file.py @@ -0,0 +1,62 @@ +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', 10, lambda x: x) + +Min = BinOperator('-', 2, AddProperties, lambda x, y: x - y) +# Pns = UnaryOperator('()', 0, lambda x: x) + diff --git a/python_symb/parse.py b/python_symb/parse.py new file mode 100644 index 0000000..c237c5a --- /dev/null +++ b/python_symb/parse.py @@ -0,0 +1,121 @@ +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} + + + + +def update_symbols_dict(): + global name_to_symbol + name_to_symbol = {sy.name:sy for sy in Symbols.instances} + + +""" +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 new file mode 100644 index 0000000..1922db7 --- /dev/null +++ b/python_symb/symbols.py @@ -0,0 +1,34 @@ +from __future__ import annotations +# from expr import Expr + + +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) + self.__class__.instances.append(self) + + """def __add__(self, other) -> Expr: + return Expr('+', [self, other])""" + diff --git a/python_symb/tools.py b/python_symb/tools.py new file mode 100644 index 0000000..3d3b00a --- /dev/null +++ b/python_symb/tools.py @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..6734322 --- /dev/null +++ b/python_symb/tree.py @@ -0,0 +1,81 @@ +from __future__ import annotations +from typing import Iterable, Generator +from collections import deque +from parse import update_symbols_dict + + +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 new file mode 100644 index 0000000..6cd3f4f --- /dev/null +++ b/python_symb/visual.py @@ -0,0 +1,123 @@ +import tkinter as tk +from expr import Expr, Var +from parse import update_symbols_dict + +class Visual: + def __init__(self): + self.root = tk.Tk() + self.root.title("Visual") + self.root.geometry("1200x1200") + + # Add a canvas on the left side of the window + self.tree_canvas = tk.Canvas(self.root, width=800, height=800, 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 "Variables" on top of the right frame, should not take all the space + self.variables_label = tk.Label(self.right_frame, text="Variables:") + self.variables_label.pack() + + # Add an entry below the label with default text x y z" + self.variables_entry = tk.Entry(self.right_frame, width=50) + self.variables_entry.insert(0, "x y z") + self.variables_entry.pack() + + # Add a button below the entry with the text "Update variables" + self.variables_button = tk.Button(self.right_frame, text="Update variables", command=self.update_variables) + self.variables_button.pack() + + + + # 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 update_variables(self): + # Get the text from the entry + text = self.variables_entry.get() + + # Create the variables + variables = text.split() + + for v in variables: + if v not in Var.instances: + Var(v) + + # Update the symbols dict + update_symbols_dict() + + + 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=400, first_y=50, x_offset=250, y_offset=200, radius=30, fact_mult=0.75): + + 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*fact_mult, y_offset*fact_mult, radius=radius*fact_mult) + + # Draw the root node + self.create_circle(first_x, first_y, radius, "red") + self.tree_canvas.create_text(first_x, first_y, text=str(tree.value)) + +if __name__ == "__main__": + Visual() + + + + + + + + +