Филарета обнови решението на 14.11.2012 12:11 (преди около 12 години)
+class Expr
+ def self.build(expression)
+ operation,a,b = expression
+ case operation
+ when :+ then Addition.build a,b
+ when :* then Multiplication.build a,b
+ when :- then Negation.build a
+ when :sin then Sine.build a
+ when :cos then Cosine.build a
+ when :variable then Variable.new a
+ when :number then Number.new a
+ end
+ end
+
+ def *(other)
+ Multiplication.new self, other
+ end
+
+ def +(other)
+ Addition.new self, other
+ end
+
+ def -@
+ Negation.new self
+ end
+end
+
+class Negation < Expr
+ attr_accessor :operand
+
+ def initialize(operand)
+ @operand = operand
+ end
+
+ def self.build(operand)
+ a = Expr.build operand
+ new a
+ end
+
+ def evaluate(environment)
+ negative = @operand.evaluate environment
+ - negative
+ end
+
+ def exact?
+ @operand.exact?
+ end
+
+ def simplify
+ if exact?
+ @operand.simplify
+ else
+ Number.new - operand
+ end
+ end
+
+ def derive(variable)
+ result = operand.derive variable
+ - result.simplify
+ end
+
+ def ==(other)
+ if other.instance_of? Negation
+ @operand == other.operand
+ else
+ false
+ end
+ end
+end
+
+class Variable < Expr
+ attr_accessor :variable
+
+ def initialize(variable)
+ @variable = variable
+ end
+
+ def derive(variable)
+ if @variable == variable
+ Number.new 1
+ else
+ Number.new 0
+ end
+ end
+
+ def evaluate(environment)
+ environment.each{ |key,value| if @variable == key then @variable = value end }
+ @variable
+ end
+
+ def simplify
+ Variable.new variable
+ end
+
+ def exact?
+ true
+ end
+
+ def ==(other)
+ if other.instance_of? Variable
+ @variable == other.variable
+ else
+ false
+ end
+ end
+end
+
+class Number < Expr
+ attr_accessor :number
+
+ def initialize(number)
+ @number = number
+ end
+
+ def derive(variable)
+ Number.new 0
+ end
+
+ def simplify
+ Number.new @number
+ end
+
+ def exact?
+ false
+ end
+
+ def evaluate(environment)
+ @number
+ end
+
+ def ==(other)
+ if other.instance_of? Number
+ @number == other.number
+ else
+ false
+ end
+ end
+end
+
+class Sine < Expr
+ attr_accessor :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def self.build(operand)
+ a = Expr.build operand
+ new a
+ end
+
+ def evaluate(environment)
+ Math.sin(@argument.evaluate environment)
+ end
+
+ def derive(variable)
+ first = Cosine.new argument.derive variable
+ second = (Variable.new variable).derive variable
+ result = first * second
+ result.simplify
+ end
+
+ def simplify
+ if @argument.exact? then @argument.simplify
+ elsif @argument.number == 0 then Number.new 0
+ elsif @argument.number == 90 then Number.new 1
+ end
+ end
+
+ def exact?
+ @argument.exact?
+ end
+
+ def ==(other)
+ if other.instance_of? Sine
+ @argument == other.argument
+ else
+ false
+ end
+ end
+end
+
+class Cosine < Expr
+ attr_accessor :argument
+
+ def initialize(argument)
+ @argument = argument
+ end
+
+ def self.build(operand)
+ a = Expr.build operand
+ new a
+ end
+
+ def evaluate(environment)
+ Math.cos(@argument.evaluate environment)
+ end
+
+ def derive(variable)
+ first = Sine.new argument.derive variable
+ second = (Variable.new variable).derive variable
+ result = first * - second
+ result.simplify
+ end
+
+ def simplify
+ if @argument.exact? then @argument.simplify
+ elsif @argument.number == 0 then Number.new 1
+ elsif @argument.number == 90 then Number.new 0
+ end
+ end
+
+ def exact?
+ @argument.exact?
+ end
+
+ def ==(other)
+ if other.instance_of? Cosine
+ @argument == other.argument
+ else
+ false
+ end
+ end
+end
+
+class Addition < Expr
+ attr_accessor :addend_1, :addend_2
+
+ def initialize(operand_1,operand_2)
+ @addend_1 = operand_1
+ @addend_2 = operand_2
+ end
+
+ def self.build(operand_1,operand_2)
+ a = Expr.build operand_1
+ b = Expr.build operand_2
+ new a,b
+ end
+
+ def derive(variable)
+ first = addend_1.derive variable
+ second = addend_2.derive variable
+ result = first + second
+ result.simplify
+ end
+
+ def simplify
+ if @addend_1.instance_of? Number and @addend_2.instance_of? Number then
+ Number.new @addend_1.number + @addend_2.number
+ elsif @addend_1.instance_of? Number and @addend_1.number == 0 then @addend_2.simplify
+ elsif @addend_2.instance_of? Number and @addend_2.number == 0 then @addend_1.simplify
+ elsif @addend_1.exact? then @addend_1.simplify + @addend_2
+ elsif @addend_2.exact? then @addend_1 + @addend_2.simplify
+ elsif @addend_1.exact? then @addend_1.simplify + @addend_2.simplify
+ end
+ end
+
+ def exact?
+ @addend_1.exact? or @addend_2.exact?
+ end
+
+ def evaluate(environment)
+ first = @addend_1.evaluate environment
+ second = @addend_2.evaluate environment
+ first + second
+ end
+
+ def ==(other)
+ if other.instance_of? Addition
+ @addend_1 == other.addend_1 and @addend_2 == other.addend_2
+ else
+ false
+ end
+ end
+end
+
+class Multiplication < Expr
+ attr_accessor :multiplicand, :multiplier
+
+ def initialize(operand_1,operand_2)
+ @multiplicand = operand_1
+ @multiplier = operand_2
+ end
+
+ def self.build(operand_1,operand_2)
+ a = Expr.build operand_1
+ b = Expr.build operand_2
+ new a,b
+ end
+
+ def derive(variable)
+ first = multiplicand.derive variable
+ second = multiplier.derive variable
+ derived_1 = Multiplication.new first, multiplier
+ derived_2 = Multiplication.new multiplicand, second
+ result = derived_1 + derived_2
+ result.simplify
+ end
+
+ def simplify
+ unless @multiplicand.exact?
+ if @multiplicand.number == 0 then @multiplicand.simplify
+ elsif @multiplicand.number == 1 then @multiplier.simplify
+ elsif @multiplicand.instance_of? Number then @multiplier.simplify
+ end
+ else
+ if @multiplier.exact? then @multiplicand.simplify * @multilier.simplify
+ elsif @multiplier.number == 0 then @multiplier.simplify
+ elsif @multiplier.number == 1 then @multiplicand.simplify
+ elsif @multiplier.instance_of? Number then @multiplicand.simplify
+ end
+ end
+ end
+
+ def exact?
+ @multiplicand.exact? or @multiplier.exact?
+ end
+
+ def evaluate(environment)
+ first = @multiplicand.evaluate environment
+ second = @multiplier.evaluate environment
+ first * second
+ end
+
+ def ==(other)
+ if other.instance_of? Multiplication
+ @multiplicand == other.multiplicand and @multiplier == other.multiplier
+ else
+ false
+ end
+ end
+end