Skip to content

Instantly share code, notes, and snippets.

@etale
Created October 4, 2011 05:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save etale/1260985 to your computer and use it in GitHub Desktop.
Save etale/1260985 to your computer and use it in GitHub Desktop.
an implementation of complex numbers with tropical flavor
# 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