#!/usr/bin/env python #DeriverTest import re LEFT = 1 RIGHT = 2 def is_between(v,mi,ma): mi = ord(mi) ma = ord(ma) v = ord(v) return mi <= v and ma >= v def is_alpha(v): return is_between(v,'a','z') def is_numeric(v): return is_between(v,'0','9') class Operator2(object): priority = 0 symbol = None priority_side = LEFT def __init__(self,left,right): self.left = left self.right = right def __repr__(self): return "(" + repr(self.left) + ") "+self.symbol+" (" + repr(self.right) + ")" def insert(self,id_dict,idv=None): return self.__class__(self.left.insert(id_dict,idv),self.right.insert(id_dict,idv)) def __eq__(self,other): return self.__class__ == other.__class__ and self.left == other.left and self.right == other.right def is_constant(self,idv=None): return self.left.is_constant(idv) and self.right.is_constant(idv) def calc(self): a = self.left.calc().value b = self.right.calc().value return Numeric(self._calc(a,b)) def _calc(self): raise "Error symbol %s not implemented" % self.symbol class Addition(Operator2): priority = 3 symbol = "+" def _calc(self,a,b): return a + b class Subtraction(Operator2): priority = 3 symbol = "-" def _calc(self,a,b): return a - b class Multiplication(Operator2): priority = 2 symbol = "*" def _calc(self,a,b): return a * b class Division(Operator2): priority = 2 symbol = "/" def _calc(self,a,b): return a/b class Power(Operator2): priority = 1 symbol = "^" def _calc(self,a,b): return a**b class Numeric(object): def __init__(self,value): self.value = value def __repr__(self): return str(self.value) def __eq__(self,other): return self.__class__ == other.__class__ and self.value == other.value def insert(self,id_dict,idv=None): return self.__class__(self.value) def is_constant(self,idv=None): return True def calc(self): return self class Var(object): def __init__(self,idv): self.idv = idv def insert(self,id_dict,idv=None): raise Exception("That shits not real") def is_constant(self,idv=None): if idv is None: return False return idv != self.idv def __repr__(self): return self.idv def calc(self): raise "Can't calculate a variable" class Parser: operators2 = dict( (cls.symbol,cls) for cls in Operator2.__subclasses__() ) @classmethod def parse(cls, term): if len(term) == 0: raise Exception("shit's empty") if len(term) == 1 and is_alpha(term): return Var(term) try: numeric_value = float(term) return Numeric(numeric_value) #return Numeric if term is numeric except ValueError: pass brackets_counter = 0 operator_match = (-1,None) for index,char in enumerate(term): if char == "(": brackets_counter+=1 elif char == ")": brackets_counter-=1 if brackets_counter < 0: raise Exception("Bracket error") elif char in cls.operators2 and brackets_counter == 0: operator_found = cls.operators2[char] if operator_match[0] < 0 or operator_found.priority > operator_match[1].priority: operator_match = (index,operator_found) if operator_match[0] >= 0: return operator_match[1]( Parser.parse( term[:operator_match[0]] ), Parser.parse( term[operator_match[0]+1:] ) ) if term[0] == "(" and term[-1] == ")": return Parser.parse(term[1:-1]) raise Exception("WTF is this shit %s" % term) class IdMark: def __init__(self,idv,constant=False): self.idv = idv self.constant = constant def insert(self,id_dict,idv): return id_dict[self.idv] def __repr__(self): if self.constant: return "IDC[%s]" % self.idv else: return "ID[%s]" % self.idv class DeriveVarIdMark: def insert(self,id_dict,idv): return Var(idv) def __repr__(self): return "X[]" class DerivationMark: def __init__(self,content): self.content = content def insert(self,id_dict,idv): return Deriver.derive(self.content.insert(id_dict,idv),idv) class DRule: def __init__(self,pattern,skeleton): self.pattern = pattern self.skeleton = skeleton def test(self,term,idv): queue = [(self.pattern,term)] id_dict = {} while len(queue) != 0: vpattern,vterm = queue[0] queue = queue[1:] if vpattern.__class__ == IdMark: if vpattern.constant and not vterm.is_constant(idv): return None elif vpattern.idv in id_dict: if id_dict[vpattern.idv] != vterm: return None else: id_dict[vpattern.idv] = vterm elif vpattern.__class__ == DeriveVarIdMark: if not (vterm.__class__ == Var and vterm.idv == idv): return None elif vpattern.__class__ == vterm.__class__: queue.append( (vpattern.left,vterm.left) ) queue.append( (vpattern.right,vterm.right) ) else: return None return id_dict class Deriver: rules = [ DRule( #dc/dx = 0 / c const IdMark("c",constant=True), Numeric(0) ), DRule( #d/dx (a+b) = da/dx + db/dx Addition(IdMark("x"),IdMark("y")), Addition(DerivationMark(IdMark("x")),DerivationMark(IdMark("y"))) ), DRule( #d/dx (a-b) = da/dx - db/dx Subtraction(IdMark("a"),IdMark("b")), Subtraction(DerivationMark(IdMark("a")),DerivationMark(IdMark("b"))) ), DRule( #d/dx (c*a) = c * da/dx Multiplication(IdMark("c",constant=True),IdMark("x")), Multiplication(IdMark("c"), DerivationMark(IdMark("x")) ) ), DRule( #dx/dx = 1 DeriveVarIdMark(), Numeric(1) ), DRule( #d/dx (x^c) = c * x ^ (c-1) Power( DeriveVarIdMark(), IdMark("c",constant=True) ), Multiplication( IdMark("c"), Power( DeriveVarIdMark(), Subtraction( IdMark("c"), Numeric(1) ) ) ) ), DRule( #d/dx (a*b) = a * db/dx + b * da/dx Multiplication( IdMark("a"), IdMark("b") ), Addition( Multiplication( IdMark("a"), DerivationMark( IdMark("b") ) ), Multiplication( IdMark("b"), DerivationMark( IdMark("a") ) ) ) ), DRule( #d/dx (a/b) = (da/dx * b - a * db/dx)/b^2 Division( IdMark("a"), IdMark("b") ), Division( Subtraction( Multiplication( DerivationMark( IdMark("a") ), IdMark("b") ), Multiplication( IdMark("a"), DerivationMark( IdMark("b") ) ) ), Power( IdMark("b"), Numeric(2) ) ) ) ] @classmethod def derive(cls,term,idv): for rule in cls.rules: id_dict = rule.test(term,idv) if id_dict is not None: return rule.skeleton.insert(id_dict,idv) raise Exception("Couldn't derive %s" % term) class SRule: def __init__(self,pattern,applier): self.pattern = pattern self.applier = applier class Simplifier: @staticmethod def simplify(term): if term.is_constant(): return term.calc() elif isinstance(term,Operator2): print ( term.__class__.__name__ ) sleft = Simplifier.simplify(term.left) sright = Simplifier.simplify(term.right) term = term.__class__(sleft,sright) if term.left.is_constant(): tleft = term.left.calc() else: tleft = term.left if term.right.is_constant(): tright = Simplifier.simplify(term.right.calc()) else: tright = term.right return term.__class__(tleft,tright) else: return term sterm = input("Input term (deriving by x): ") term = Parser.parse(sterm) print ( "Deriving %s" % term ) dterm = Deriver.derive(term,"x") print ( "DTerm: %s" % dterm ) sterm = Simplifier.simplify(dterm) print ( "Result: %s" % sterm )