Камелия обнови решението на 11.11.2012 03:57 (преди около 12 години)
+class Expr
+ def self.build(expr_tree)
+ if expr_tree.length == 3
+ Binary.build expr_tree
+ else
+ Unary.build expr_tree
+ end
+ end
+end
+
+class Binary < Expr
+ def self.build(expr_tree)
+ case expr_tree.shift
+ when :+ then Addition.new Expr.build(expr_tree.shift), Expr.build(expr_tree.shift)
+ when :* then Multiplication.new Expr.build(expr_tree.shift), Expr.build(expr_tree.shift)
+ end
+ end
+end
+
+class Addition < Binary
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left, @right = left, right
+ end
+
+ def evaluate(environment = {})
+ (@left.evaluate environment) + (@right.evaluate environment)
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ return @left.simplify if @right.exact? and @right.evaluate == 0
+ return @right.simplify if @left.exact? and @left.evaluate == 0
+ Addition.new @left.simplify, @right.simplify
+ end
+
+ def derive(variable)
+ Addition.new(@left.derive(variable), @right.derive(variable)).simplify
+ end
+
+ def exact?
+ @left.exact? and @right.exact?
+ end
+
+ def ==(other)
+ self.class == other.class and left == other.left and right == other.right
+ end
+end
+
+class Multiplication < Binary
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left, @right = left, right
+ end
+
+ def evaluate(environment = {})
+ (@left.evaluate environment) * (@right.evaluate environment)
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ if @left.exact?
+ return Number.new 0 if @left.evaluate == 0
+ return @right.simplify if @left.evaluate == 1
+ end
+ if @right.exact?
+ return Number.new 0 if @right.evaluate == 0
+ return @left.simplify if @right.evaluate == 1
+ end
+ Multiplication.new @left.simplify, @right.simplify
+ end
+
+ def derive(variable)
+ left = Multiplication.new @left.derive(variable), @right
+ right = Multiplication.new @right, @left.derive(variable)
+ Addition.new(left, right).simplify
+ end
+
+ def exact?
+ @left.exact? and @right.exact?
+ end
+
+ def ==(other)
+ self.class == other.class and left == other.left and right == other.right
+ end
+end
+
+class Unary < Expr
+ def self.build(expr_tree)
+ case expr_tree.shift
+ when :number then Number.new expr_tree.shift
+ when :variable then Variable.new expr_tree.shift
+ when :- then Negation.new Expr.build expr_tree.shift
+ when :sin then Sine.new Expr.build expr_tree.shift
+ when :cos then Cosine.new Expr.build expr_tree.shift
+ end
+ end
+end
+
+class Negation < Unary
+ attr_reader :arg
+
+ def initialize(arg)
+ @arg = arg
+ end
+
+ def evaluate(environment = {})
+ -(@arg.evaluate environment)
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ Negation.new @arg.simplify
+ end
+
+ def derive(variable)
+ Negation.new(@arg.derive(variable)).simplify
+ end
+
+ def exact?
+ @arg.exact?
+ end
+
+ def ==(other)
+ self.class == other.class and arg == other.arg
+ end
+end
+
+class Sine < Unary
+ attr_reader :arg
+
+ def initialize(arg)
+ @arg = arg
+ end
+
+ def evaluate(environment = {})
+ Math.sin @arg.evaluate environment
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ Sine.new @arg.simplify
+ end
+
+ def derive(variable)
+ Multiplication.new(@arg.derive(variable), Cosine.new(@arg)).simplify
+ end
+
+ def exact?
+ @arg.exact?
+ end
+
+ def ==(other)
+ self.class == other.class and arg == other.arg
+ end
+end
+
+class Cosine < Unary
+ attr_reader :arg
+
+ def initialize(arg)
+ @arg = arg
+ end
+
+ def evaluate(environment = {})
+ Math.cos @arg.evaluate environment
+ end
+
+ def simplify
+ return Number.new evaluate if exact?
+ Cosine.new @arg.simplify
+ end
+
+ def derive(variable)
+ Multiplication.new(@arg.derive(variable), Negation.new(Sine.new(@arg))).simplify
+ end
+
+ def exact?
+ @arg.exact?
+ end
+
+ def ==(other)
+ self.class == other.class and arg == other.arg
+ end
+end
+
+class Variable < Unary
+ attr_reader :arg
+
+ def initialize(arg)
+ @arg = arg
+ end
+
+ def evaluate(environment = {})
+ raise "uninitialized variable" if not environment.has_key? @arg
+ environment.fetch @arg
+ end
+
+ def simplify
+ self
+ end
+
+ def derive(variable)
+ return Number.new 1 if variable == @arg
+ return Number.new 0
+ end
+
+ def exact?
+ false
+ end
+
+ def ==(other)
+ self.class == other.class and arg == other.arg
+ end
+end
+
+class Number < Unary
+ attr_reader :arg
+
+ def initialize(arg)
+ @arg = arg
+ end
+
+ def evaluate(environment = {})
+ @arg
+ end
+
+ def simplify
+ self
+ end
+
+ def derive(variable)
+ Number.new 0
+ end
+
+ def exact?
+ true
+ end
+
+ def ==(other)
+ self.class == other.class and arg == other.arg
+ end
+end