Теодор обнови решението на 14.11.2012 06:03 (преди около 12 години)
+class Expr
+ def self.build(parse_array)
+ case parse_array[0]
+ when :number then Number.new parse_array[1]
+ when :variable then Variable.new parse_array[1]
+ when :- then -(build parse_array[1])
+ when :+ then (build parse_array[1]) + (build parse_array[2])
+ when :* then (build parse_array[1]) * (build parse_array[2])
+ when :sin then Sine.new build parse_array[1]
+ when :cos then Cosine.new build parse_array[1]
+ end
+ end
+
+ def +(other)
+ Addition.new self, other
+ end
+
+ def -@
+ Negation.new self
+ end
+
+ def *(other)
+ Multiplication.new self, other
+ end
+end
+
+class Unary < Expr
+ attr_reader :operand
+
+ def initialize(operand)
+ @operand = operand
+ end
+
+ def ==(other)
+ self.class == other.class and self.operand == other.operand
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ @operand.exact?
+ end
+end
+
+class Binary < Expr
+ attr_reader :left_operand, :right_operand
+
+ def initialize(left_operand, right_operand)
+ @left_operand = left_operand
+ @right_operand = right_operand
+ end
+
+ def ==(other)
+ self.class == other.class and
+ self.left_operand == other.left_operand and
+ self.right_operand == other.right_operand
+ end
+
+ def exact?
+ @left_operand.exact? and @right_operand.exact?
+ end
+end
+
+class Number < Unary
+ def evaluate(environment = {})
+ @operand
+ end
+
+ def derive(variable)
+ Number.new 0
+ end
+
+ def exact?
+ true
+ end
+end
+
+class Variable < Unary
+ def evaluate(environment = {})
+ fail "Variable #@operand is undefined" unless environment.has_key? @operand
+ environment[@operand]
+ end
+
+ def derive(variable)
+ if variable == operand
+ Number.new 1
+ else
+ Number.new 0
+ end
+ end
+
+ def exact?
+ false
+ end
+end
+
+class Negation < Unary
+ def evaluate(environment = {})
+ -1 * (@operand.evaluate environment)
+ end
+
+ def derive(variable)
+ (-(@operand.derive(variable))).simplify
+ end
+
+ def simplify
+ if exact? then return Number.new(-1 * operand.evaluate) end
+ if operand.simplify.exact? then return Number.new(-1 * operand.simplify.evaluate) end
+ if operand.simplify.class == Negation then return (operand.simplify).operand end
+ -(operand.simplify)
+ end
+end
+
+class Sine < Unary
+ def evaluate(environment = {})
+ Math.sin(@operand.evaluate environment)
+ end
+
+ def derive(variable)
+ (@operand.derive(variable) * (Cosine.new @operand)).simplify
+ end
+
+ def simplify
+ if exact? then return Number.new evaluate end
+ if @operand.simplify.exact? then return Number.new @operand.simplify.evaluate end
+ Sine.new @operand.simplify
+ end
+end
+
+class Cosine < Unary
+ def evaluate(environment = {})
+ Math.cos(@operand.evaluate environment)
+ end
+
+ def derive(variable)
+ (@operand.derive(variable) * -(Sine.new @operand)).simplify
+ end
+
+ def simplify
+ if exact? then return Number.new evaluate end
+ if @operand.simplify.exact? then return Number.new @operand.simplify.evaluate end
+ Cosine.new @operand.simplify
+ end
+end
+
+class Addition < Binary
+ def evaluate(environment = {})
+ (@left_operand.evaluate environment) + (@right_operand.evaluate environment)
+ end
+
+ def derive(variable)
+ (@left_operand.derive(variable) + @right_operand.derive(variable)).simplify
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ if @left_operand.simplify.exact? and @left_operand.simplify.evaluate == 0
+ return @right_operand.simplify
+ end
+ if @right_operand.simplify.exact? and @right_operand.simplify.evaluate == 0
+ return @left_operand.simplify
+ end
+ @left_operand.simplify + @right_operand.simplify
+ end
+end
+
+class Multiplication < Binary
+ def evaluate(environment = {})
+ (@left_operand.evaluate environment) * (@right_operand.evaluate environment)
+ end
+
+ def derive(variable)
+ (@left_operand.derive(variable) * @right_operand +
+ @left_operand * @right_operand.derive(variable)).simplify
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ if @left_operand.simplify.exact?
+ return Number.new 0 if @left_operand.simplify.evaluate == 0
+ return @right_operand.simplify if @left_operand.simplify.evaluate == 1
+ end
+ if @right_operand.simplify.exact?
+ return Number.new 0 if @right_operand.simplify.evaluate == 0
+ return @left_operand.simplify if @right_operand.simplify.evaluate == 1
+ end
+ @left_operand.simplify * @right_operand.simplify
+ end
+end