Даяна обнови решението на 13.11.2012 21:24 (преди около 12 години)
+class Expr
+ include Math
+ attr_accessor :expression, :variables, :any_variables
+ def initialize(expression)
+ @expression = expression
+ @variables = []
+ @any_variables = false
+ @expression.flatten.map do |item|
+ @any_variables = true if item == :variable
+ end
+ end
+
+ def self.build(expression)
+ self.new(expression)
+ end
+
+ def == (other)
+ @expression == other.expression
+ end
+
+ def evaluate(environment = {})
+ environment.map do |key, value|
+ @variables << key
+ @variables << value
+ end
+ evaluation(@expression)
+ end
+
+ def evaluation(expression)
+ case expression[0]
+ when :number then expression[1]
+ when :variable then check_variable(expression[1])
+ when :- then -evaluation(expression[1])
+ when :sin then sin(evaluation expression[1])
+ when :cos then cos(evaluation expression[1])
+ else [evaluation(expression[1]), evaluation(expression[2])].inject(expression[0])
+ end
+ end
+
+ def check_variable(variable)
+ @variables.each_index { |index| return @variables[index + 1] if @variables[index] == variable }
+ end
+
+ def simplify
+ if !@any_variables and @expression[0] != :-
+ return Expr.build([:number, evaluate])
+ elsif !@any_variables
+ Expr.build([:-, [:number, -evaluate]])
+ end
+ Expr.build(Binary.simplify_binary(@expression))
+ end
+
+ def derive(variable)
+ Expr.build(Binary.derive_binary(@expression, variable)).simplify
+ end
+end
+
+class Unary < Expr
+ def self.simplify_unary(expression)
+ simple_expression = Expr.build(expression[1]).simplify
+ if expression[0] == :- and simple_expression.expression[0] == :number
+ [:number, - simple_expression.expression[1]]
+ elsif expression[0] == :sin and simple_expression == Expr.build([:number, 0])
+ [:number, 0]
+ elsif Expr.build(expression[1]).any_variables
+ [expression[0], simple_expression.expression]
+ else
+ [:number, Expr.build([expression[0], (simple_expression.expression)]).evaluate]
+ end
+ end
+
+ def self.derive_unary(expression, variable)
+ item = Expr.build(expression[1])
+ if expression[0] == :sin
+ [:*, item.derive(variable).expression, [:cos, item.simplify.expression]]
+ elsif expression[0] == :cos
+ [:*, item.derive(variable).expression, [:-, [:sin, item.simplify.expression]]]
+ end
+ end
+end
+
+class Binary < Expr
+ def self.simplify_binary(expression)
+ case expression[0]
+ when :number then return expression
+ when :variable then return expression
+ when :sin then Unary.simplify_unary(expression)
+ when :cos then Unary.simplify_unary(expression)
+ when :+ then Addition.simple_add(expression)
+ when :* then Multiplication.simple_multy(expression)
+ when :- then [:-, simplify_binary(expression[1])]
+ end
+ end
+
+ def self.derive_binary(expression, variable)
+ case expression [0]
+ when :number then return [:number, 0]
+ when :variable then check_variable(expression[1], variable)
+ when :+ then Addition.derive_add(expression, variable)
+ when :* then Multiplication.derive_multy(expression, variable)
+ when :- then return [:-, Expr.build(expression[1]).derive(variable).expression]
+ when :sin then Unary.derive_unary(expression, variable)
+ when :cos then Unary.derive_unary(expression, variable)
+ end
+ end
+
+ def self.check_variable(variable1, variable2)
+ return [:number, 1] if variable1 == variable2
+ [:number, 0]
+ end
+end
+
+class Multiplication < Binary
+ def self.simple_multy(expression)
+ expression1 = simplify_binary(expression[1])
+ expression2 = simplify_binary(expression[2])
+ if expression1 == [:number, 0] or expression2 == [:number, 0]
+ return [:number, 0]
+ elsif expression2 == [:number, 1]
+ return expression[1]
+ elsif expression1 == [:number, 1]
+ return expression[2]
+ end
+ [expression[0], expression1, expression2]
+ end
+
+ def self.derive_multy(expression, variable)
+ a = expression[1]
+ b = expression[2]
+ [:+, [:*, derive_binary(a, variable), b], [:*, a, derive_binary(b, variable)]]
+ end
+end
+
+class Addition < Binary
+ def self.simple_add(expression)
+ if simplify_binary(expression[2]) == [:number, 0]
+ return simplify_binary(expression[1])
+ elsif simplify_binary(expression[1]) == [:number, 0]
+ return simplify_binary(expression[2])
+ end
+ [expression[0], simplify_binary(expression[1]), simplify_binary(expression[2])]
+ end
+
+ def self.derive_add(expression, variable)
+ [:+, derive_binary(expression[1], variable), derive_binary(expression[2], variable)]
+ end
+end