Георги обнови решението на 14.11.2012 01:15 (преди около 12 години)
+class Expr
+ attr_reader :object
+
+ def initialize(object)
+ @object = object
+ end
+
+ def self.build(expression)
+ case expression.count
+ when 2 then Unary.build expression
+ when 3 then Binary.build expression
+ end
+ end
+
+ def evaluate(environment = {})
+ @object.evaluate environment
+ end
+
+ def derive(variable)
+ @object.derive variable
+ end
+
+ def simplify
+ evaluate if exact?
+ @object.simplify
+ end
+
+ def exact?
+ @object.exact?
+ end
+
+ def +(other)
+ Addition.new self.simplify, other.simplify
+ end
+
+ def *(other)
+ Multiplication.new self.simplify, other.simplify
+ end
+
+ def -@
+ Negation.new self.simplify
+ end
+end
+
+class Unary < Expr
+ attr_reader :object
+
+ def self.build(expression)
+ case expression[0]
+ when :number then Number.build expression[1]
+ when :variable then Variable.build expression[1]
+ when :- then Negation.build expression[1]
+ when :sin then Sine.build expression[1]
+ when :cos then Cosine.build expression[1]
+ end
+ end
+
+ def exact?
+ @object.exact?
+ end
+
+ def ==(other)
+ return false if self.class != other.class
+ @object == other.object
+ end
+end
+
+class Binary < Expr
+ attr_reader :object1, :object2
+
+ def initialize(object1, object2)
+ @object1, @object2 = object1, object2
+ end
+
+ def self.build(expression)
+ case expression[0]
+ when :+ then Addition.build(expression[1], expression[2])
+ when :* then Multiplication.build(expression[1], expression[2])
+ end
+ end
+
+ def exact?
+ @object1.exact? and @object2.exact?
+ end
+
+ def ==(other)
+ return false if self.class != other.class
+ object1 == other.object1 and object2 == other.object2
+ end
+end
+
+class Number < Unary
+ def self.build(value)
+ new value
+ end
+
+ def evaluate(environment = {})
+ @object
+ end
+
+ def derive(variable)
+ new 0
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ true
+ end
+end
+
+class Variable < Unary
+ def self.build(expression)
+ new expression
+ end
+
+ def evaluate(environment = {})
+ if environment.has_key? @object
+ environment[@object]
+ else
+ raise "There's no variable #{@variable} in the environment"
+ end
+ end
+
+ def derive(variable)
+ Number.new variable == @object ? 1 : 0
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ false
+ end
+end
+
+class Negation < Unary
+ def self.build(expression)
+ -Expr.build(expression)
+ end
+
+ def evaluate(environment = {})
+ -@object.evaluate(environment)
+ end
+
+ def derive(variable)
+ -@object.derive(variable)
+ end
+
+ def simplify
+ return Number.new(evaluate) if exact?
+ -@object.simplify
+ end
+end
+
+class Sine < Unary
+ def self.build(expression)
+ new Expr.build(expression)
+ end
+
+ def evaluate(environment = {})
+ Math.sin @object.evaluate(environment)
+ end
+
+ def derive(variable)
+ @object.derive(variable) * Cosine.new(@object)
+ end
+
+ def simplify
+ return Number.new(evaluate) if exact?
+ Sine.new @object.simplify
+ end
+end
+
+class Cosine < Unary
+ def self.build(expression)
+ new Expr.build(expression)
+ end
+
+ def evaluate(environment = {})
+ Math.cos @object.evaluate(environment)
+ end
+
+ def derive(variable)
+ @object.derive(variable) * -Sine.new(@object)
+ end
+
+ def simplify
+ return Number.new(evaluate) if exact?
+ Cosine.new @object.simplify
+ end
+end
+
+class Addition < Binary
+ def self.build(expression1, expression2)
+ Expr.build(expression1) + Expr.build(expression2)
+ end
+
+ def evaluate(environment = {})
+ @object1.evaluate(environment) + @object2.evaluate(environment)
+ end
+
+ def derive(variable)
+ result = @object1.derive(variable) + @object2.derive(variable)
+ result.simplify
+ end
+
+ def simplify
+ zero_as_object = Expr.build([:number, 0])
+
+ return Number.new(evaluate) if exact?
+ return @object1.simplify if @object2 == zero_as_object
+ return @object2.simplify if @object1 == zero_as_object
+
+ (@object1.simplify + @object2.simplify)
+ end
+end
+
+class Multiplication < Binary
+ def self.build(expression1, expression2)
+ Expr.build(expression1) * Expr.build(expression2)
+ end
+
+ def evaluate(environment = {})
+ @object1.evaluate(environment) * @object2.evaluate(environment)
+ end
+
+ def derive(variable)
+ result = (@object1.derive(variable) * @object2) + (@object1 * @object2.derive(variable))
+ result.simplify
+ end
+
+ def simplify
+ one_as_object = Expr.build([:number, 1])
+ zero_as_object = Expr.build([:number, 0])
+
+ return Number.new(evaluate) if exact?
+ return @object1.simplify if @object2 == one_as_object
+ return @object2.simplify if @object1 == one_as_object
+ return Number.new 0 if @object1 == zero_as_object || @object2 == zero_as_object
+
+ (@object1.simplify * @object2.simplify).simplify
+ end
+end