Илия обнови решението на 14.11.2012 16:57 (преди около 12 години)
+
+class Expr
+ def self.build(array)
+ type = array[0]
+ return Negation.new(array) if type == :-
+ return Addition.new(array) if type == :+
+ return Multiplication.new(array) if type == :*
+ class_of_type = {number: Number, variable: Variable, sin: Sine, cos: Cosine}
+ class_of_type[type].new(array)
+ end
+
+ def +(other)
+ Addition.new([:+,self,other])
+ end
+
+ def *(other)
+ Multiplication.new([:*,self,other])
+ end
+
+ def -
+ Negation.new([:-,self])
+ end
+end
+
+class Unary < Expr
+ def initialize(array)
+ @type = array.shift
+ @a = Expr.build array.shift
+ end
+
+ def exact?
+ @a.exact?
+ end
+
+ def simplify
+ return [:number, evaluate] if exact?
+ Expr.build [@type, @a.simplify]
+ end
+end
+
+class Binary < Expr
+ def initialize(array)
+ @type = array.shift
+ @a = Expr.build array.shift
+ @b = Expr.build array.shift
+ end
+
+ def exact?
+ @a.exact? and @b.exact?
+ end
+
+ def simplify
+ return [:number, evaluate] if exact?
+ Expr.build [@type, @a.simplify, @b.simplify]
+ end
+end
+
+class Number < Unary
+ def initialize(array)
+ @type, @a = array
+ end
+
+ def exact?
+ true
+ end
+
+ def evaluate(environment = {})
+ @a
+ end
+
+ def simplify
+ self
+ end
+
+ def derive(variable)
+ Expr.build([:number,0])
+ end
+end
+
+class Variable < Unary
+ def initialize(array)
+ @type, @a = array
+ end
+
+ def exact?
+ false
+ end
+
+ def evaluate(environment = {})
+ return environment[@a] if environment[@a]
+ raise 'There is an uninitialized variable'
+ end
+
+ def simplify
+ self
+ end
+
+ def derive(variable)
+ return Expr.build([:number,1]) if @a == variable
+ Expr.build([:number,0])
+ end
+end
+
+class Negation < Unary
+ def evaluate(environment = {})
+ -@a.evaluate(environment)
+ end
+
+ def derive(variable)
+ -@a.derive(variable)
+ end
+end
+
+class Addition < Binary
+ def evaluate(environment = {})
+ @a.evaluate(environment) + @b.evaluate(environment)
+ end
+
+ def simplify
+ return [:number, evaluate] if exact?
+ return @b.simplify if @a.simplify.zero?
+ return @a.simplify if @b.simplify.zero?
+ Expr.build [@type, @a.simplify, @b.simplify]
+ end
+
+ def derive(variable)
+ @a.derive(variable) + @b.derive(variable)
+ end
+end
+
+class Multiplication < Binary
+ def evaluate(environment = {})
+ @a.evaluate(environment) * @b.evaluate(environment)
+ end
+
+ def simplify
+ return [:number, evaluate] if exact?
+ return @b.simplify if @a.simplify == 1
+ return @a.simplify if @b.simplify == 1
+ return 0 if @b.simplify.zero? or @a.simplify.zero?
+ Expr.build [@type, @a.simplify, @b.simplify]
+ end
+
+ def derive(variable)
+ @a.derive(variable) * @b + @a * @b.derive(variable)
+ end
+end
+
+class Sine < Unary
+ def evaluate(environment = {})
+ Math.sin @a.evaluate(environment)
+ end
+
+ def derive(variable)
+ @a.derive(variable) * Cosine.new(@a)
+ end
+end
+
+class Cosine < Unary
+ def evaluate(environment = {})
+ Math.cos @a.evaluate(environment)
+ end
+
+ def derive(variable)
+ @a.derive(variable) * (-Sine.new(@a))
+ end
+end