Николай обнови решението на 11.11.2012 03:35 (преди около 12 години)
+class Expr
+ attr_reader :expression
+
+ def initialize(expression_tree)
+ if expression_tree.length == 2
+ @expression = Unary.new(expression_tree)
+ else
+ @expression = Binary.new(expression_tree)
+ end
+ end
+
+ def self.build(expression_tree)
+ Expr.new(expression_tree)
+ end
+
+ def ==(other)
+ to_array == other.to_array
+ end
+
+ def method_missing(name, *args, &block)
+ @expression.send(name, *args, &block)
+ end
+
+ def to_array
+ @expression.expression.expression
+ end
+end
+
+class Unary < Expr
+ def initialize(expression_tree)
+ case expression_tree[0]
+ when :number then @expression = Number.new (expression_tree)
+ when :variable then @expression = Variable.new(expression_tree)
+ when :- then @expression = Negation.new(expression_tree)
+ when :sin then @expression = Sine.new (expression_tree)
+ when :cos then @expression = Cosine.new (expression_tree)
+ end
+ end
+
+ def argument
+ self[1]
+ end
+end
+
+class Binary < Expr
+ def initialize(expression_tree)
+ case expression_tree[0]
+ when :+ then @expression = Addition.new (expression_tree)
+ when :* then @expression = Multiplication.new(expression_tree)
+ end
+ end
+
+ def left_argument
+ self[1]
+ end
+
+ def right_argument
+ self[2]
+ end
+end
+
+class Number < Unary
+ attr_reader :expression
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def exact?
+ true
+ end
+
+ def simplify
+ Expr.new(@expression)
+ end
+
+ def evaluate(scope = {})
+ argument
+ end
+
+ def derive(variable)
+ Expr.new([:number, 0])
+ end
+end
+
+class Variable < Unary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ scope[argument]
+ end
+
+ def exact?
+ false
+ end
+
+ def simplify
+ Expr.new([:variable, argument])
+ end
+
+ def derive(variable)
+ variable == argument ? Expr.new([:number, 1]) : Expr.new([:number, 0])
+ end
+end
+
+class Negation < Unary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ -Expr.new(argument).evaluate(scope)
+ end
+
+ def exact?
+ Expr.new(argument).exact?
+ end
+
+ def simplify
+ if exact?
+ Expr.new([:number, evaluate])
+ else
+ Expr.new([:-, Expr.new(argument).simplify.to_array])
+ end
+ end
+
+ def derive(variable)
+ new_argument = Expr.new(argument).derive(variable).to_array
+ Expr.new([:-, new_argument]).simplify
+ end
+end
+
+class Sine < Unary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ Math.sin Expr.new(argument).evaluate(scope)
+ end
+
+ def exact?
+ Expr.new(argument).exact?
+ end
+
+ def simplify
+ if exact?
+ Expr.new [:number, evaluate]
+ else
+ Expr.new([:sin, Expr.new(argument).simplify.to_array])
+ end
+ end
+
+ def derive(variable)
+ inner_derivative = Expr.new(argument).derive(variable).to_array
+ Expr.new([:*, inner_derivative, [:cos, argument]]).simplify
+ end
+end
+
+class Cosine < Unary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ Math.cos Expr.new(argument).evaluate(scope)
+ end
+
+ def exact?
+ Expr.new(argument).exact?
+ end
+
+ def simplify
+ if exact?
+ result = Expr.new [:number, evaluate]
+ else
+ result = Expr.new([:cos, Expr.new(argument).simplify.to_array])
+ end
+ end
+
+ def derive(variable)
+ inner_derivative = Expr.new(argument).derive(variable).to_array
+ Expr.new([:*, inner_derivative, [:-, [:sin, argument]]]).simplify
+ end
+end
+
+class Addition < Binary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ Expr.new(left_argument).evaluate(scope) + Expr.new(right_argument).evaluate(scope)
+ end
+
+ def exact?
+ Expr.new(left_argument).exact? && Expr.new(right_argument).exact?
+ end
+
+ def simplify
+ if Expr.new(left_argument).exact? && Expr.new(left_argument).evaluate == 0
+ simplified = Expr.new(right_argument).simplify
+ else
+ if Expr.new(right_argument).exact? && Expr.new(right_argument).evaluate == 0
+ simplified = Expr.new(left_argument).simplify
+ else
+ new_left_argument = Expr.new(left_argument).simplify.to_array
+ new_right_argument = Expr.new(right_argument).simplify.to_array
+ simplified = Expr.new([:+, new_left_argument, new_right_argument])
+ end
+ end
+ if exact?
+ Expr.new([:number, evaluate])
+ else
+ simplified
+ end
+ end
+
+ def derive(variable)
+ derivative_of_left_argument = Expr.new(left_argument).derive(variable).to_array
+ derivative_of_right_argument = Expr.new(right_argument).derive(variable).to_array
+ Expr.new([:+, derivative_of_left_argument, derivative_of_right_argument]).simplify
+ end
+end
+
+class Multiplication < Binary
+ def initialize(expression_tree)
+ @expression = expression_tree
+ end
+
+ def evaluate(scope = {})
+ result = 0 if Expr.new(left_argument).exact? && Expr.new(left_argument).evaluate(scope) == 0
+ result = 0 if Expr.new(right_argument).exact? && Expr.new(right_argument).evaluate(scope) == 0
+ if result != 0
+ result = Expr.new(left_argument).evaluate(scope) * Expr.new(right_argument).evaluate(scope)
+ else
+ result
+ end
+ end
+
+ def exact?
+ result = Expr.new(left_argument).exact? && Expr.new(right_argument).exact?
+ result ||= Expr.new(left_argument).exact? && Expr.new(left_argument).evaluate == 0
+ result ||= Expr.new(right_argument).exact? && Expr.new(right_argument).evaluate == 0
+ end
+
+ def simplify
+ simplified_left = Expr.new(left_argument).simplify
+ simplified_right = Expr.new(right_argument).simplify
+ if simplified_left.exact? && simplified_left.evaluate == 1
+ simplified = simplified_right
+ else
+ if simplified_right.exact? && simplified_right.evaluate == 1
+ simplified = simplified_left
+ else
+ simplified = Expr.new([:*, simplified_left.to_array, simplified_right.to_array])
+ end
+ end
+ if exact?
+ Expr.new([:number, evaluate])
+ else
+ simplified
+ end
+ end
+
+ def derive(variable)
+ left_derivative = Expr.new(left_argument).derive(variable)
+ right_derivative = Expr.new(right_argument).derive(variable)
+ new_left_argument = [:*, left_derivative.to_array, right_argument]
+ new_right_argument = [:*, left_argument, right_derivative.to_array]
+ Expr.new([:+, new_left_argument, new_right_argument]).simplify
+ end
+end