Created
October 4, 2011 05:48
-
-
Save etale/1260985 to your computer and use it in GitHub Desktop.
an implementation of complex numbers with tropical flavor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# tropical.rb | |
# an implementation of complex numbers with tropical flavor | |
# | |
# self == e^{ord + 2 \pi i arg} | |
class Class | |
def get *args, &block | |
(new *args, &block).identity | |
end | |
end | |
class Numeric | |
@@pool = {} | |
def identity; @@pool[self] ||= self; end | |
def get *args; self.class.get *args; end | |
def eql? a; self.class.eql? a.class; end | |
def coerce a; [a, to_c]; end | |
MathMethods = (Math.methods - Kernel.methods).map {|m| m.intern } | |
def method_missing method, *args | |
if MathMethods.include? method | |
begin | |
Math.send method, self, *args | |
rescue Errno::EDOM | |
to_c.send method, *args | |
end | |
else | |
super | |
end | |
end | |
def unit; self < zero ? -unity : unity; end | |
def body; self / unit; end | |
def zero?; eql? zero; end | |
def unity?; eql? unity; end | |
def body?; eql? body; end | |
def unit?; eql? unit; end | |
def inverse; 1.0 / self; end | |
def ** a | |
_ = power a | |
(Float === _ and _.nan?) ? to_c**a : _ | |
end | |
def to_c; self * Complex::UNITY; end | |
def i; self * Complex::I; end | |
def x; to_c; end | |
def c_; (self + inverse) * 0.5; end | |
def s_; (self - inverse) * 0.5; end | |
def t_; (self - inverse) / (self + inverse); end | |
def _c; self + (self**2 - unity)**0.5; end | |
def _s; self + (self**2 + unity)**0.5; end | |
def _t; ((unity + self) / (unity - self))**0.5; end | |
end | |
class Float | |
def zero; 0.0; end; def unity; 1.0; end | |
def unit; self < 0.0 ? -1.0 : 1.0; end | |
def succ; self + 1.0; end | |
alias_method :power, :** | |
remove_method :** | |
alias_method :_coerce, :coerce | |
def coerce a | |
case a | |
when Complex | |
super | |
else | |
_coerce a; | |
end | |
end | |
def negligible? | |
abs < EPSILON * 2**4 | |
end | |
def to_c | |
raise if infinite? or nan? | |
super | |
end | |
end | |
class Integer | |
def zero; 0; end; def unity; 1; end | |
end | |
class Fixnum | |
alias_method :power, :** | |
remove_method :** | |
end | |
class Bignum | |
alias_method :power, :** | |
remove_method :** | |
end | |
class Complex < Numeric | |
PI2 = Math::PI * 2.0 | |
def initialize ord, arg | |
arg %= 1.0 | |
unless ord.nil? | |
ord = 0.0 if ord.negligible? | |
arg = 0.0 if arg.negligible? or (1.0 - arg).negligible? | |
end | |
@ord, @arg = ord, arg | |
end | |
attr_reader :ord, :arg | |
def _arg; arg < 0.5 ? arg : arg - 1.0; end | |
def abs; zero? ? 0.0 : ord.exp; end | |
def amp; _arg * PI2; end | |
def _re; (amp.hypot ord).log; end | |
def _im; amp.atan2 ord; end | |
def re; abs * amp.cos; end | |
def im; abs * amp.sin; end | |
def eql? a | |
super and ord.eql? a.ord and arg.eql? a.arg | |
end | |
def hash | |
ord.hash ^ arg.hash | |
end | |
def self.ord a; get 1.0 * a, 0.0; end | |
def self.arg a; get 0.0, 1.0 / a; end | |
ZERO = get nil, 0.0 | |
UNITY = ord 0; E = ord 1; I = arg 4 | |
def zero; get nil, 0.0; end; def unity; get 0.0, 0.0; end | |
def body; get ord, 0.0; end; def unit; get 0.0, arg; end | |
def conj; get ord, -arg; end | |
def _i; zero? ? self : (get ord, arg + 0.25); end | |
def i_; zero? ? self : (get ord, arg - 0.25); end | |
def shift; zero? ? self : (get ord.succ, arg); end | |
def cast a | |
case a | |
when self.class | |
a | |
when Float, Integer | |
case a <=> 0 | |
when 0; zero | |
when 1; get a .log, 0.0 | |
when -1; get (-a).log, 0.5 | |
end | |
else | |
raise | |
end | |
end | |
def coerce a | |
[(cast a), self] | |
end | |
def to_c; self; end | |
def <=> a | |
a = cast a | |
return 0 if zero? and a.zero? | |
return _arg.unit <=> 0 if a.zero? | |
return 0 <=> a._arg.unit if zero? | |
[_arg, _arg.unit * ord] <=> [a._arg, a._arg.unit * a.ord] | |
end | |
def * a | |
a = cast a | |
return zero if zero? or a.zero? | |
get ord + a.ord, arg + a.arg | |
end | |
def inverse | |
return if zero? | |
get -ord, -arg | |
end | |
def / a | |
a = cast a | |
self * a.inverse | |
end | |
def log | |
return if zero? | |
unity? ? zero : (get _re, _im / PI2) | |
end | |
def exp | |
zero? ? unity : (get re, im / PI2) | |
end | |
def ** a | |
return unity if a.zero? | |
return zero if zero? | |
case a | |
when Integer, Float | |
get ord * a, _arg * a | |
else | |
(log * a).exp | |
end | |
end | |
def succ; exp.shift.log; end | |
def + a | |
a = cast a | |
return a if zero? | |
return self if a.zero? | |
return a + self if a.ord > ord | |
return zero if eql? -a | |
self * (a / self).succ | |
end | |
def -@ | |
zero? ? self : (get ord, arg + 0.5) | |
end | |
def - a | |
self + -a | |
end | |
def _at2 a; (_i + a) / (hypot a); end | |
def atan2 a; (_at2 a).log.i_; end | |
def cos; _i.cosh; end; def cosh; exp.c_; end | |
def sin; _i.sinh.i_; end; def sinh; exp.s_; end | |
def tan; _i.tanh.i_; end; def tanh; exp.t_; end | |
def acos; acosh.i_; end; def acosh; _c.log; end | |
def asin; _i.asinh.i_; end; def asinh; _s.log; end | |
def atan; _i.atanh.i_; end; def atanh; _t.log; end | |
def sqrt; self**0.5; end | |
def hypot a; (self**2 + a**2).sqrt; end | |
def log10; log / 10.log; end | |
def frexp; [unit, ord]; end | |
def ldexp a; self * (get a, 0.0); end | |
def erfc; raise NotImplementedError; end | |
def erf; raise NotImplementedError; end | |
def reim | |
return [0.0, 0.0] if zero? | |
x, y = re, im | |
x = 0.0 if x.negligible? | |
y = 0.0 if y.negligible? | |
[x, y] | |
end | |
def inspect | |
return '0.0' if zero? | |
if $classic | |
re, im = reim | |
reim * (im < 0 ? '' : '+') + '.i' | |
else | |
ord.inspect + arg.inspect[1..-1] + ' X' | |
end | |
end | |
def to_s; inspect; end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment