Йордан обнови решението на 14.11.2012 13:33 (преди около 12 години)
+class Expr
+ def self.build(tree)
+ case tree.first
+ when :+ then Addition.new tree[1], tree[2]
+ when :* then Multiplication.new tree[1], tree[2]
+ when :number then Number.new tree[1]
+ when :variable then Variable.new tree[1]
+ when :- then Negation.new tree[1]
+ when :sin then Sine.new tree[1]
+ when :cos then Cosine.new tree[1]
+ end
+ end
+
+ def -
+ Negation.new self
+ end
+end
+
+class Unary < Expr
+ def ==(other)
+ self.class == other.class && self.value == other.value
+ end
+end
+
+class Binary < Expr
+ def ==(other)
+ self.class == other.class &&
+ self.first == other.first &&
+ self.second == other.second
+ end
+
+ def +(other)
+ self.evaluate + other.evaluate
+ end
+
+ def *(other)
+ self.evaluate * other.evaluate
+ end
+
+ def value
+ self
+ end
+end
+
+class Number < Unary
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def evaluate(environment = {})
+ @value
+ end
+
+ def derive(variable)
+ Number.new 0
+ end
+
+ def simplify
+ Number.new @value
+ end
+end
+
+class Addition < Binary
+ attr_reader :first, :second
+
+ def initialize(first, second)
+ if first.is_a? Expr
+ @first = first
+ @second = second
+ else
+ @first = Expr.build first
+ @second = Expr.build second
+ end
+ end
+
+ def evaluate(environment = {})
+ @first.evaluate(environment) + @second.evaluate(environment)
+ end
+
+ def derive(variable)
+ Addition.new(@first.derive(variable), @second.derive(variable)).simplify
+ end
+
+ def simplify
+ first_simplified = @first.simplify
+ second_simplified = @second.simplify
+
+ if first_simplified.class == Number && second_simplified.class == Number
+ Number.new (first_simplified.value + second_simplified.value)
+ elsif first_simplified.value == 0
+ second_simplified
+ elsif second_simplified.value == 0
+ first_simplified
+ else
+ Addition.new first_simplified, second_simplified
+ end
+ end
+end
+
+class Multiplication < Binary
+ attr_reader :first, :second
+
+ def initialize(first, second)
+ if first.is_a? Expr
+ @first = first
+ @second = second
+ else
+ @first = Expr.build first
+ @second = Expr.build second
+ end
+ end
+
+ def evaluate(environment = {})
+ @first.evaluate(environment) * @second.evaluate(environment)
+ end
+
+ def derive(variable)
+ Addition.new(Multiplication.new(@first.derive(variable), @second),
+ Multiplication.new(@first, second.derive(variable))).simplify
+ end
+
+ def simplify
+ if @first.simplify.class == Number && @second.simplify.class == Number
+ Number.new (@first.simplify.value * @second.simplify.value)
+ elsif @first.simplify.value == 0 || second.simplify.value == 0
+ Number.new 0
+ elsif @first.simplify.value == 1
+ @second.simplify
+ elsif @second.simplify.value == 1
+ @first.simplify
+ else
+ Multiplication.new @first.simplify, @second.simplify
+ end
+ end
+end
+
+class Variable < Unary
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def evaluate(environment = {})
+ environment[value] || (raise "Variable #{value} does not have value!")
+ end
+
+ def derive(variable)
+ if @value == variable
+ Number.new 1
+ else
+ Number.new 0
+ end
+ end
+
+ def simplify
+ self
+ end
+end
+
+class Negation < Unary
+ attr_reader :value
+
+ def initialize(value)
+ if value.is_a? Expr
+ @value = value
+ else
+ @value = Expr.build value
+ end
+ end
+
+ def evaluate(environment = {})
+ -@value.evaluate(environment)
+ end
+
+ def derive(variable)
+ Negation.new(@value.derive(variable)).simplify
+ end
+
+ def simplify
+ simplified_value = @value.simplify
+ if simplified_value.class == Negation
+ simplified_value.value
+ else
+ Negation.new simplified_value
+ end
+ end
+end
+
+class Sine < Unary
+ attr_reader :value
+
+ def initialize(value)
+ if value.is_a? Expr
+ @value = value
+ else
+ @value = Expr.build value
+ end
+ end
+
+ def evaluate(environment = {})
+ Math.sin @value.evaluate(environment)
+ end
+
+ def derive(variable)
+ Multiplication.new(@value.derive(variable), Cosine.new(@value))
+ end
+
+ def simplify
+ simplified_value = @value
+ if simplified_value.class == Number
+ Number.new Math.sin(simplified_value.value)
+ else
+ Sine.new simplified_value
+ end
+ end
+end
+
+class Cosine < Unary
+ attr_reader :value
+
+ def initialize(value)
+ if value.is_a? Expr
+ @value = value
+ else
+ @value = Expr.build value
+ end
+ end
+
+ def evaluate(environment = {})
+ Math.cos @value.evaluate(environment)
+ end
+
+ def derive(variable)
+ Multiplication.new(@value.derive(variable), -Cosine.new(@value))
+ end
+
+ def simplify
+ simplified_value = @value.simplify
+ if simplified_value.class == Number
+ Number.new Math.cos(simplified_value.value)
+ else
+ Cosine.new simplified_value
+ end
+ end
+end