Кирчо обнови решението на 11.11.2012 18:03 (преди около 12 години)
+class Expr
+ def self.build(expr_tree)
+ operation = expr_tree[0]
+ if expr_tree.length == 2
+ if operation == :number or operation == :variable
+ Unary.build operation, expr_tree[1]
+ else
+ Unary.build operation, build(expr_tree[1])
+ end
+ else
+ Binary.build operation, build(expr_tree[1]), build(expr_tree[2])
+ end
+ end
+end
+
+class Unary < Expr
+ def self.build(operation, argument)
+ case operation
+ when :sin then Sine.new argument
+ when :cos then Cosine.new argument
+ when :- then Negation.new argument
+ when :number then Number.new argument
+ when :variable then Variable.new argument
+ end
+ end
+end
+
+class Binary < Expr
+ def self.build(operation, left, right)
+ case operation
+ when :+ then Addition.new left, right
+ when :* then Multiplication.new left, right
+ end
+ end
+end
+
+class Addition < Binary
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def ==(other)
+ other.class == Addition and
+ left == other.left and
+ right == other.right
+ end
+
+ def evaluate(environment = {})
+ left.evaluate(environment) + right.evaluate(environment)
+ end
+
+ def exact?
+ left.exact? and right.exact?
+ end
+
+ def simplify
+ new_left, new_right = left.simplify, right.simplify
+
+ if new_left.exact? and new_right.exact?
+ Number.new (new_left.evaluate + new_right.evaluate)
+ elsif new_left.exact? and new_left.evaluate == 0
+ new_right
+ elsif new_right.exact? and new_right.evaluate == 0
+ new_left
+ else
+ Addition.new new_left, new_right
+ end
+ end
+
+ def derive(variable)
+ new_left = left.derive variable
+ new_right = right.derive variable
+
+ (Addition.new new_left, new_right).simplify
+ end
+end
+
+class Multiplication < Binary
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def ==(other)
+ other.class == Multiplication and
+ left == other.left and
+ right == other.right
+ end
+
+ def evaluate(environment = {})
+ left.evaluate(environment) * right.evaluate(environment)
+ end
+
+ def exact?
+ left.exact? and right.exact?
+ end
+
+ def simplify
+ new_left, new_right = left.simplify, right.simplify
+
+ if new_left.exact? and new_right.exact?
+ Number.new (new_left.evaluate * new_right.evaluate)
+ elsif new_left.exact? and (new_left.evaluate == 1 or new_left.evaluate == 0)
+ new_left.evaluate == 1 ? new_right : Number.new(0)
+ elsif new_right.exact? and (new_right.evaluate == 1 or new_right.evaluate == 0)
+ new_right.evaluate == 1 ? new_left : Number.new(0)
+ else
+ Multiplication.new new_left, new_right
+ end
+ end
+
+ def derive(variable)
+ new_left = left.derive variable
+ new_right = right.derive variable
+ left_mult = Multiplication.new new_left, right
+ right_mult = Multiplication.new left, new_right
+
+ (Addition.new left_mult, right_mult).simplify
+ end
+end
+
+class Number < Unary
+ attr_reader :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def ==(other)
+ other.class == Number and argument == other.argument
+ end
+
+ def evaluate(environment = {})
+ argument
+ end
+
+ def exact?
+ true
+ end
+
+ def simplify
+ dup
+ end
+
+ def derive(variable)
+ Number.new 0
+ end
+end
+
+class Variable < Unary
+ attr_reader :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def ==(other)
+ other.class == Variable and argument == other.argument
+ end
+
+ def evaluate(environment = {})
+ raise ArgumentError unless environment[argument]
+
+ environment[argument]
+ end
+
+ def exact?
+ false
+ end
+
+ def simplify
+ dup
+ end
+
+ def derive(variable)
+ argument == variable ? Number.new(1) : Number.new(0)
+ end
+end
+
+class Negation < Unary
+ attr_reader :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def ==(other)
+ other.class == Negation and argument == other.argument
+ end
+
+ def evaluate(environment = {})
+ -(argument.evaluate environment)
+ end
+
+ def exact?
+ argument.exact?
+ end
+
+ def simplify
+ new_argument = argument.simplify
+ if new_argument.exact?
+ Number.new (-new_argument.evaluate)
+ else
+ Negation.new new_argument
+ end
+ end
+
+ def derive(variable)
+ (Negation.new argument.derive(variable)).simplify
+ end
+end
+
+class Sine < Unary
+ attr_reader :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def ==(other)
+ other.class == Sine and argument == other.argument
+ end
+
+ def evaluate(environment = {})
+ Math.sin argument.evaluate(environment)
+ end
+
+ def exact?
+ argument.exact?
+ end
+
+ def simplify
+ new_argument = argument.simplify
+ if new_argument.exact?
+ Number.new (new_argument.evaluate)
+ else
+ Sine.new new_argument
+ end
+ end
+
+ def derive(variable)
+ argument_derivative = argument.derive variable
+
+ (Multiplication.new argument_derivative, Cosine.new(argument)).simplify
+ end
+end
+
+class Cosine < Unary
+ attr_reader :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def ==(other)
+ other.class == Cosine and argument == other.argument
+ end
+
+ def evaluate(environment = {})
+ Math.cos argument.evaluate(environment)
+ end
+
+ def exact?
+ argument.exact?
+ end
+
+ def simplify
+ new_argument = argument.simplify
+ if new_argument.exact?
+ Number.new (new_argument.evaluate)
+ else
+ Cosine.new new_argument
+ end
+ end
+
+ def derive(variable)
+ argument_derivative = argument.derive variable
+
+ (Multiplication.new argument_derivative, Negation.new(Sine.new(argument))).simplify
+ end
+end