Георги обнови решението на 13.11.2012 23:18 (преди около 12 години)
+class Expr #Using as a leaf node
+ def self.build(expression_tree)
+ if (expression_tree.kind_of? Array)
+ length = expression_tree.size
+ if length == 3
+ return build_binary_expr(expression_tree.first,Expr.build(expression_tree.fetch(1)),
+ Expr.build(expression_tree.fetch(2)))
+ elsif length == 2
+ return build_unary_expr(expression_tree.first,Expr.build(expression_tree.fetch(1)))
+ end
+ else
+ Expr.new(expression_tree)
+ end
+ end
+
+ def initialize(primitive)
+ @expr = primitive
+ end
+
+ def evaluate(environment={})
+ @expr
+ end
+
+ def simplify
+ @expr
+ end
+
+ def derive(variable)
+ @expr
+ end
+
+ def to_s
+ @expr.to_s
+ end
+
+ def ==(other)
+ to_s == other.to_s
+ end
+
+ private
+ def self.build_binary_expr(operation, expr1, expr2)
+ case operation
+ when :+
+ return AdditionExpr.new(expr1,expr2)
+ when :*
+ return MultiplicationExpr.new(expr1,expr2)
+ end
+ end
+
+ def self.build_unary_expr(operation,expr1)
+ case operation
+ when :sin
+ return SineExpr.new(expr1)
+ when :cos
+ return CosineExpr.new(expr1)
+ when :-
+ return NegateExpr.new(expr1)
+ when :number
+ return NumberExpr.new(expr1)
+ when :variable
+ return VariableExpr.new(expr1)
+ end
+ end
+end
+
+class UnaryExpr < Expr
+ def initialize(expr)
+ @expr = expr
+ end
+
+ def to_s
+ @expr.evaluate.to_s
+ end
+
+end
+
+class BinaryExpr < Expr
+ def initialize(expr_a, expr_b)
+ @expr_a = expr_a
+ @expr_b = expr_b
+ end
+
+ def to_string(operation)
+ "#{@expr_a}#{operation}#{@expr_b}"
+ end
+
+ def is_constant_expr
+ (@expr_a.is_constant_expr) && (@expr_b.is_constant_expr)
+ end
+end
+
+class AdditionExpr < BinaryExpr
+ def evaluate(environment={})
+ (@expr_a.evaluate environment) + (@expr_b.evaluate environment)
+ end
+ def simplify
+ simplified_a = @expr_a.simplify
+ simplified_b = @expr_b.simplify
+ return simplified_a if simplified_b== 0
+ return simplified_b if simplified_a == 0
+ return NumberExpr.new(Expr.new(evaluate)) if is_constant_expr
+
+ return AdditionExpr.new(simplified_a, simplified_b)
+ end
+
+ def derive(variable)
+ AdditionExpr.new((@expr_a.derive variable) ,(@expr_b.derive variable)).simplify
+ end
+
+ def to_s
+ to_string('+')
+ end
+end
+
+class MultiplicationExpr < BinaryExpr
+ def evaluate(environment={})
+ (@expr_a.evaluate environment) * (@expr_b.evaluate environment)
+ end
+
+ def simplify
+ simplified_a = @expr_a.simplify
+ simplified_b = @expr_b.simplify
+
+ if (simplified_a == NumberExpr.new(Expr.new(0)) || simplified_b == NumberExpr.new(Expr.new(0)))
+ return NumberExpr.new(Expr.new(0))
+ end
+
+ return simplified_a if simplified_b == NumberExpr.new(Expr.new(1))
+ return simplified_b if simplified_a == NumberExpr.new(Expr.new(1))
+ return NumberExpr.new(Expr.new(evaluate)) if is_constant_expr
+ return MultiplicationExpr.new(simplified_a, simplified_b)
+ end
+
+ def derive(variable)
+ expr_a = MultiplicationExpr.new((@expr_a.derive variable), @expr_b)
+ expr_b = MultiplicationExpr.new(@expr_a, (@expr_b.derive variable))
+ (AdditionExpr.new(expr_a,expr_b)).simplify
+ end
+
+ def to_s
+ to_string('*')
+ end
+end
+
+
+class VariableExpr < UnaryExpr
+ def initialize(expr)
+ @expr = expr
+ end
+
+ def simplify
+ self
+ end
+
+ def derive(variable)
+ NumberExpr.new(Expr.new(@expr.to_s == variable.to_s ? 1: 0 ))
+ end
+
+ def evaluate(environment={})
+ return @expr.evaluate unless environment.has_key?(@expr.evaluate)
+
+ environment[@expr.evaluate]
+ end
+
+ def is_constant_expr
+ false
+ end
+
+end
+
+class NumberExpr < UnaryExpr
+ def initialize(wrapper)
+ @expr = wrapper
+ end
+ def evaluate(environment={})
+ @expr.evaluate environment
+ end
+
+ def is_constant_expr
+ true
+ end
+
+ def derive(variable)
+ NumberExpr.new(Expr.new(0))
+ end
+
+ def simplify
+ self
+ end
+end
+
+class SineExpr < UnaryExpr
+ def evaluate(environment={})
+ Math.sin(super.evaluate environment)
+ end
+
+ def to_s
+ "sin(#{super.to_s})"
+ end
+
+ def simplify
+ NumberExpr.new(Expr.new(0)) if evaluate == 0
+ end
+end
+
+class CosineExpr < UnaryExpr
+ def evaluate(environment={})
+ Math.cos(super.evaluate environment)
+ end
+ def to_s
+ "sin(#{super.to_s})"
+ end
+end
+
+class NegateExpr < UnaryExpr
+ def evaluate(environment={})
+ MultiplicationExpr.new(Expr.new(-1), @expr).evaluate environment
+ end
+end