Мирослав обнови решението на 14.11.2012 10:49 (преди около 12 години)
+class Simplifier
+ def Simplifier.simplify(expr)
+ case expr[0]
+ when :number then expr
+ when :variable then expr
+ when :- then [:-, simplify(expr[1])]
+ when :* then expr = Simplifier.verify_multiplication(expr)
+ when :sin then expr = Simplifier.verify_sin(expr)
+ when :cos then expr
+ else expr = Simplifier.verify_addition(expr)
+ end
+ end
+
+ def Simplifier.verify_sin(expr)
+ arg = simplify(expr[1])
+ return arg if arg == [:number, 0]
+ [expr[0], arg]
+ end
+
+ def Simplifier.verify_addition(expr)
+ num, expr1, expr2 = [:number, 0], simplify(expr[1]), simplify(expr[2])
+ return expr2 if expr1 == num
+ return expr1 if expr2 == num
+ [expr[0], expr1, expr2]
+ end
+
+ def Simplifier.verify_multiplication(expr)
+ num_zero, num_one = [:number, 0], [:number, 1]
+ expr1, expr2 = simplify(expr[1]), simplify(expr[2])
+ return num_zero if expr1 == num_zero || expr2 == num_zero
+ return expr2 if expr1 == num_one
+ return expr1 if expr2 == num_one
+ [expr[0], expr1, expr2]
+ end
+end
+
+class Derive
+ def Derive.derive(expr, arg)
+ case expr[0]
+ when :number then [:number, 0]
+ when :variable then variable_evaluate(expr[1], arg)
+ when :- then [expr[0], derive(expr[1], arg)]
+ when :sin then [:*, derive(expr[1], arg), [:cos, expr[1]]]
+ when :cos then [:*, derive(expr[1], arg), [:-, [:sin, expr[1]]]]
+ when :+ then [:+, derive(expr[1], arg), derive(expr[2], arg)]
+ when :* then complex_multiplication(expr, arg)
+ end
+ end
+
+ def Derive.variable_evaluate(expr, arg)
+ return [:number, 1] if arg == expr
+ [:number, 0]
+ end
+
+ def Derive.complex_multiplication(expr, arg)
+ product = [:+]
+ product << [:*, derive(expr[1], arg), expr[2]]
+ product << [:*, expr[1], derive(expr[2], arg)]
+ product
+ end
+end
+
+class Expr
+ attr_reader :expr
+ include Math
+
+ def initialize(s_expression)
+ @expr = s_expression
+ @vars = false
+ end
+
+ def Expr.build(s_expression)
+ self.new(s_expression)
+ end
+
+ def exact?(expr = @expr)
+ case expr[0]
+ when :variable then @vars = true
+ when :number then @vars
+ when :+ then exact?(expr[1]) || exact?(expr[2])
+ when :* then exact?(expr[1]) || exact?(expr[2])
+ else exact?(expr[1])
+ end
+ end
+
+ def ==(expr)
+ @expr == expr.expr
+ end
+
+ def evaluate(environment = {})
+ calc_expr(@expr, environment)
+ end
+
+ def calc_expr(expr, env = {})
+ return expr if expr.kind_of? Integer
+ return expr if expr.kind_of? Float
+ case expr[0]
+ when :number then calc_expr(expr[1], env)
+ when :variable then env.fetch(expr[1])
+ when :sin then sin(calc_expr(expr[1], env))
+ when :cos then cos(calc_expr(expr[1], env))
+ when :- then calc_expr([:*, [:number, -1], expr[1]],env)
+ else calc_expr(expr[1], env).send expr[0], calc_expr(expr[2], env)
+ end
+ end
+
+ def simplify
+ @vars = false
+ @simplified = Simplifier.simplify(@expr)
+ if !Expr.build(@simplified).exact?
+ Expr.build([:number, Expr.build(@simplified).evaluate])
+ else
+ Expr.build(@simplified)
+ end
+ end
+
+ def derive(arg)
+ expr = Derive.derive(Simplifier.simplify(@expr), arg)
+ @simplified = Simplifier.simplify(expr)
+ if !Expr.build(@simplified).exact?
+ Expr.build([:number, Expr.build(@simplified).evaluate])
+ else
+ Expr.build(@simplified)
+ end
+ end
+end