Милан обнови решението на 12.11.2012 18:04 (преди около 12 години)
+class Expr
+ attr_reader :expression
+
+ def initialize(expression)
+ @expression = expression
+ end
+
+ def evaluate(variables = {})
+ @expression.evaluate variables
+ end
+
+ def self.build(expression)
+ Expr.new(Expr.build_expression(expression))
+ end
+
+ def simplify
+ Expr.new @expression.simplify
+ end
+
+ def derive(argument)
+ @expression.derive(argument)
+ Expr.new @expression.derive(argument).simplify
+ end
+
+ def ==(other)
+ @expression == other.expression
+ end
+
+ def self.build_expression(expression)
+ type, first_value, second_value = expression
+ case type
+ when :number then Number.new first_value
+ when :variable then Variable.new first_value
+ when :- then Negation.new build_expression(first_value)
+ when :sin then Sine.new build_expression(first_value)
+ when :cos then Cosine.new build_expression(first_value)
+ when :+ then Addition.new(build_expression(first_value), build_expression(second_value))
+ when :* then Multiplication.new(build_expression(first_value), build_expression(second_value))
+ end
+ end
+end
+
+class Number < Expr
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def simplify
+ Number.new @value
+ end
+
+ def exact?
+ true
+ end
+
+ def evaluate(environment = {})
+ @value
+ end
+
+ def derive(argument)
+ Number.new 0
+ end
+
+ def ==(other)
+ @value == other.value
+ end
+end
+
+class Addition < Expr
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def simplify
+ if @left.exact? and @right.exact?
+ Number.new(@left.evaluate + @right.evaluate)
+ elsif @left.exact?
+ simplify_result(@left, @right)
+ elsif @right.exact?
+ simplify_result(@right, @left)
+ else
+ Addition.new(@left.simplify, @right.simplify)
+ end
+ end
+
+ def exact?
+ @left.exact? && @right.exact?
+ end
+
+ def evaluate(environment = {})
+ @left.evaluate(environment) + @right.evaluate(environment)
+ end
+
+ def derive(argument)
+ Addition.new(@left.derive(argument), @right.derive(argument))
+ end
+
+ def ==(other)
+ self.class == other.class ? (@left == other.left and @right == other.right) : false
+ end
+
+ private
+ def simplify_result(operand_main, operand_secondary)
+ evaluation = operand_main.evaluate
+ evaluation.zero? ? operand_secondary.simplify : Number.new(operand_main.evaluate)
+ end
+end
+
+class Multiplication < Expr
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def simplify
+ if @left.exact? and @right.exact?
+ Number.new(@left.evaluate * @right.evaluate)
+ elsif @left.exact?
+ simplify_result(@left, @right)
+ elsif @right.exact?
+ simplify_result(@right, @left)
+ else
+ Multiplication.new(@left.simplify, @right.simplify)
+ end
+ end
+
+ def exact?
+ @left.exact? && @right.exact?
+ end
+
+ def evaluate(environment = {})
+ @left.evaluate(environment) * @right.evaluate(environment)
+ end
+
+ def derive(argument)
+ left_argument = Multiplication.new(@left.derive(argument), @right)
+ right_argument = Multiplication.new(@left, @right.derive(argument))
+ Addition.new(left_argument, right_argument)
+ end
+
+ def ==(other)
+ self.class == other.class ? (@left == other.left and @right == other.right) : false
+ end
+
+ private
+ def simplify_result(operand_main, operand_secondary)
+ evaluation = operand_main.evaluate
+ if evaluation == 0
+ Number.new 0
+ elsif evaluation == 1
+ operand_secondary.simplify
+ else
+ Multiplication.new(Number.new(evaluation), operand_secondary.simplify).simplify
+ end
+ end
+end
+
+class Variable < Expr
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def simplify
+ Variable.new @value
+ end
+
+ def exact?
+ false
+ end
+
+ def evaluate(environment = {})
+ raise "Use of unassigned local variable #@value" unless environment.has_key?(@value)
+ environment[@value]
+ end
+
+ def derive(argument)
+ @value == argument ? Number.new(1) : Number.new(0)
+ end
+
+ def ==(other)
+ self.class == other.class ? @value == other.value : false
+ end
+end
+
+class Negation < Expr
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def simplify
+ @value.exact? ? Number.new(evaluate) : Negation.new(@value.simplify)
+ end
+
+ def exact?
+ @value.exact?
+ end
+
+ def evaluate(environment = {})
+ -@value.evaluate(environment)
+ end
+
+ def derive(argument)
+ Negation.new(@value.derive(argument))
+ end
+
+ def ==(other)
+ self.class == other.class ? @value == other.value : false
+ end
+end
+
+class Sine < Expr
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def simplify
+ @value.exact? ? Number.new(evaluate) : Sine.new(@value.simplify)
+ end
+
+ def exact?
+ @value.exact?
+ end
+
+ def evaluate(environment = {})
+ Math.sin(@value.evaluate(environment))
+ end
+
+ def derive(argument)
+ left_argument = @value.derive argument
+ right_argument = Cosine.new @value
+ Multiplication.new(left_argument, right_argument)
+ end
+
+ def ==(other)
+ self.class == other.class ? @value == other.value : false
+ end
+end
+
+class Cosine < Expr
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def simplify
+ @value.exact? ? Number.new(evaluate) : Cosine.new(@value.simplify)
+ end
+
+ def exact?
+ @value.exact?
+ end
+
+ def evaluate(environment = {})
+ Math.cos(@value.evaluate(environment))
+ end
+
+ def derive(argument)
+ left_argument = @value.derive argument
+ right_argument = Negation.new(Sine.new(@value))
+ Multiplication.new(left_argument, right_argument)
+ end
+
+ def ==(other)
+ self.class == other.class ? @value == other.value : false
+ end
+end