lib/dydx/algebra/set.rb in dydx-0.1.3 vs lib/dydx/algebra/set.rb in dydx-0.1.4
- old
+ new
@@ -1,35 +1,212 @@
-require 'dydx/algebra/set/base'
-require 'dydx/algebra/set/num'
-require 'dydx/algebra/set/fixnum'
-require 'dydx/algebra/set/float'
-require 'dydx/algebra/set/symbol'
-require 'dydx/algebra/set/e'
-require 'dydx/algebra/set/pi'
-require 'dydx/algebra/set/log'
-require 'dydx/algebra/set/sin'
-require 'dydx/algebra/set/cos'
-require 'dydx/algebra/set/tan'
+require 'dydx/algebra/operator/parts/base'
+require 'dydx/algebra/operator/parts/general'
+require 'dydx/algebra/operator/parts/formula'
+require 'dydx/algebra/operator/parts/inverse'
+require 'dydx/algebra/operator/parts/num'
+require 'dydx/algebra/operator/inverse'
+require 'dydx/algebra/operator/formula'
+require 'dydx/algebra/operator/num'
+require 'dydx/algebra/operator/general'
+
+require 'dydx/algebra/formula'
+require 'dydx/algebra/inverse'
+
module Dydx
module Algebra
module Set
- def e0
- eval("$e0 ||= Num.new(0)")
+ module Base
+ include Helper
+
+ # TODO: Pi should not have attr_accessor
+ def self.included(_klass)
+ attr_accessor :n, :x
+ alias_method :d, :differentiate
+ end
+
+ def initialize(x = nil)
+ case self
+ when Num
+ @n = x
+ when Sin, Cos, Tan, Log, Log10, Log2
+ @x = x
+ end
+ end
+
+ def to_s
+ case self
+ when Num then n.to_s
+ when Pi then 'pi'
+ when E then 'e'
+ when Sin then "sin( #{x} )"
+ when Cos then "cos( #{x} )"
+ when Tan then "tan( #{x} )"
+ when Log then "log( #{x} )"
+ when Log10 then "log10( #{x} )"
+ when Log2 then "log2( #{x} )"
+ end
+ end
+
+ def to_f
+ case self
+ when Num then n.to_f
+ when Pi then Math::PI
+ when E then Math::E
+ when Symbol then fail ArgumentError
+ when Sin then Math.sin(x.to_f)
+ when Cos then Math.cos(x.to_f)
+ when Tan then Math.tan(x.to_f)
+ when Log then Math.log(x.to_f)
+ when Log10 then Math.log(x.to_f, 10)
+ when Log2 then Math.log(x.to_f, 2)
+ end
+ end
+
+ def subst(hash = {})
+ case self
+ when Num, Pi, E
+ self
+ when Symbol
+ hash[self] || self
+ when Sin then sin(x.subst(hash))
+ when Cos then cos(x.subst(hash))
+ when Tan then tan(x.subst(hash))
+ when Log then log(x.subst(hash))
+ when Log10 then log10(x.subst(hash))
+ when Log2 then log2(x.subst(hash))
+ end
+ end
+
+ def differentiate(sym = :x)
+ case self
+ when Num, Pi, E then e0
+ when Symbol then self == sym ? e1 : e0
+ when Sin then cos(x) * x.d(sym)
+ when Cos then -1 * sin(x) * x.d(sym)
+ when Tan then 1 / (cos(x) ** 2)
+ when Log then x.d(sym) / (x)
+ when Log10 then x.d(sym) / (x * log(10))
+ when Log2 then x.d(sym) / (x * log(2))
+ end
+ end
end
- def e1
- eval("$e1 ||= Num.new(1)")
+ class Num
+ include Base
+ include Operator::Num
+ %w(> >= < <=).each do |operator|
+ define_method(operator) do |x|
+ x = x.n if x.is_a?(Num)
+ n.send(operator, x)
+ end
+ end
end
- def _(num)
- if num >= 0
- eval("$p#{num} ||= Num.new(num)")
- else
- eval("$n#{-1 * num} ||= Num.new(num)")
+
+ class Pi
+ include Base
+ include Operator::General
+ end
+
+ class E
+ include Base
+ include Operator::General
+ end
+
+ class Sin
+ include Base
+ include Operator::General
+ end
+
+ class Cos
+ include Base
+ include Operator::General
+ end
+
+ class Tan
+ include Base
+ include Operator::General
+ end
+
+ class Log
+ include Base
+ include Operator::General
+ end
+
+ class Log10
+ include Base
+ include Operator::General
+ end
+
+ class Log2
+ include Base
+ include Operator::General
+ end
+
+ Symbol.class_eval do
+ include Base
+ include Operator::General
+ end
+
+ numeric_proc = Proc.new do
+ include Helper
+
+ def subst(_hash = {})
+ self
end
+
+ def differentiate(_sym = :x)
+ e0
+ end
+ alias_method :d, :differentiate
+
+ alias_method :addition, :+
+ alias_method :subtraction, :-
+ alias_method :multiplication, :*
+ alias_method :division, :/
+ alias_method :exponentiation, :**
+ alias_method :modulation, :%
+
+ ope_to_str = {
+ addition: :+,
+ subtraction: :-,
+ multiplication: :*,
+ division: :/,
+ exponentiation: :**,
+ modulation: :%
+ }
+ %w(+ - * / ** %).each do |operator|
+ define_method(operator) do |g|
+ if g.is_a?(Symbol) ||
+ g.is_a?(Formula) ||
+ g.is_a?(Base)
+
+ _(self).send(operator.to_sym, g)
+ else
+ send(ope_to_str.key(operator.to_sym), g)
+ end
+ end
+ end
+ if self == Rational
+ def to_s
+ "( #{numerator} / #{denominator} )"
+ end
+ end
end
+ Float.class_eval(&numeric_proc)
+ Fixnum.class_eval(&numeric_proc)
+ Rational.class_eval(&numeric_proc)
+
+ def e0
+ eval('$e0 ||= _(0)')
+ end
+
+ def e1
+ eval('$e1 ||= _(1)')
+ end
+
def pi
$pi ||= Pi.new
end
def e
@@ -38,47 +215,107 @@
def oo
Float::INFINITY
end
+ # TODO: Method has too many lines. [13/10]
def log(formula)
- if formula.multiplication?
+ if formula.formula?(:*)
f, g = formula.f, formula.g
log(f) + log(g)
- elsif formula.exponentiation?
+ elsif formula.formula?(:**)
f, g = formula.f, formula.g
g * log(f)
- elsif formula.is_1?
+ elsif formula.one?
e0
elsif formula.is_a?(E)
e1
else
Log.new(formula)
end
end
- def sin(x)
- multiplier = x.is_multiple_of(pi)
- if multiplier.is_a?(Num)
+ def log2(formula)
+ # TODO: refactor with log function.
+ if formula.formula?(:*)
+ f, g = formula.f, formula.g
+ log2(f) + log2(g)
+ elsif formula.formula?(:**)
+ f, g = formula.f, formula.g
+ g * log2(f)
+ elsif formula.one?
e0
+ elsif formula.is_a?(Num)
+ (formula.n == 2) ? e1 : log2(formula.n)
+ elsif formula == 2
+ e1
else
- Sin.new(x)
+ Log2.new(formula)
end
end
- def cos(x)
- multiplier = x.is_multiple_of(pi)
- if multiplier.is_a?(Num) && multiplier.n % 2 == 0
+ def log10(formula)
+ # TODO: refactor with log function.
+ if formula.formula?(:*)
+ f, g = formula.f, formula.g
+ log10(f) + log10(g)
+ elsif formula.formula?(:**)
+ f, g = formula.f, formula.g
+ g * log10(f)
+ elsif formula.one?
+ e0
+ elsif formula.is_a?(Num)
+ (formula.n == 10) ? e1 : log10(formula.n)
+ elsif formula == 10
e1
- elsif multiplier.is_a?(Num) && multiplier.n % 2 == 1
- _(-1)
else
- Cos.new(x)
+ Log10.new(formula)
end
end
+ # TODO: We should negative num
+ def sin(x)
+ return Sin.new(x) unless x.multiple_of?(pi) && (x / pi).num?
+
+ radn = (x / pi)
+ loop do
+ break if radn < 2
+ radn -= 2
+ end
+
+ case radn
+ when 0 then 0
+ when _(1) / 2 then 1
+ when 1 then 0
+ when _(3) / 2 then -1
+ else Sin.new(x)
+ end
+ end
+
+ def cos(x)
+ return Cos.new(x) unless x.multiple_of?(pi) && (x / pi).num?
+
+ radn = (x / pi)
+ loop do
+ break if radn < 2
+ radn -= 2
+ end
+
+ case radn
+ when 0 then 1
+ when _(1) / 2 then 0
+ when 1 then -1
+ when _(3) / 2 then 0
+ else Sin.new(x)
+ end
+ end
+
def tan(x)
- Tan.new(x)
+ if x == 0
+ 0
+ else
+ Tan.new(x)
+ end
end
end
end
end