# Numerical Array Extention for Ruby
# (C) Copyright 2000-2003 by Masahiro TANAKA
#
# This program is free software.
# You can distribute/modify this program
# under the same terms as Ruby itself.
# NO WARRANTY.
#
class NArray
def integer?
self.typecode==NArray::BYTE ||
self.typecode==NArray::SINT ||
self.typecode==NArray::LINT
end
def complex?
self.typecode==NArray::DCOMPLEX ||
self.typecode==NArray::SCOMPLEX
end
def all?
where.size == size
end
def any?
where.size > 0
end
def none?
where.size == 0
end
def ==(other)
if other.kind_of?(NArray)
(shape == other.shape) && eq(other).all?
else
false
end
end
def rank_total(*ranks)
if ranks.size>0
idx = []
ranks.each{|i| idx.push(*i)}
# ranks is expected to be, e.g., [1, 3..5, 7]
a = self.shape
n = 1
idx.each{|i| n *= a[i]}
n
else
self.total
end
end
# Statistics
def mean(*ranks)
if integer?
a = self.to_f
else
a = self
end
a = NArray.ref(a)
a.sum(*ranks) / (rank_total(*ranks))
end
def stddev(*ranks)
if integer?
a = self.to_f
else
a = self
end
a = NArray.ref(a)
n = rank_total(*ranks)
NMath::sqrt( (( a-a.accum(*ranks).div!(n) )**2).sum(*ranks)/(n-1) )
end
def median(rank=nil)
shape = self.shape
rank = shape.size-1 if rank==nil
s = sort(rank).reshape!(true,*shape[rank+1..-1])
n = s.shape[0]
if n%2==1
s[n/2,false]
else
s[n/2-1..n/2,false].sum(0)/2
end
end
# Normal distributed random number; valid for floating point types
def randomn
size = self.size
case type = self.typecode
when COMPLEX; type=FLOAT
when SCOMPLEX; type=SFLOAT
when FLOAT
when SFLOAT
else
raise TypeError, "NArray type must be (S)FLOAT or (S)COMPLEX."
end
rr = NArray.new(type,size)
xx = NArray.new(type,size)
i = 0
while i < size
n = size-i
m = ((n+Math::sqrt(n))*1.27).to_i
x = NArray.new(type,m).random!(1) * 2 - 1
y = NArray.new(type,m).random!(1) * 2 - 1
r = x**2 + y**2
idx = (r<1).where
idx = idx[0...n] if idx.size > n
if idx.size>0
rr[i] = r[idx]
xx[i] = x[idx]
i += idx.size
end
end
# Box-Muller transform
rr = ( xx * NMath::sqrt( -2 * NMath::log(rr) / rr ) )
# finish
rr.reshape!(*self.shape) if self.rank > 1
rr = rr.to_type(self.typecode) if type!=self.typecode
if RUBY_VERSION < "1.8.0"
self.type.refer(rr)
else
self.class.refer(rr)
end
end
alias randomn! randomn
#SFloatOne = NArray.sfloat(1).fill!(1)
end
module NMath
PI = Math::PI
E = Math::E
def recip x
1/x.to_f
end
# Trigonometric function
def csc x
1/sin(x)
end
def csch x
1/sinh(x)
end
def acsc x
asin(1/x.to_f)
end
def acsch x
asinh(1/x.to_f)
end
def sec x
1/cos(x)
end
def sech x
1/cosh(x)
end
def asec x
acos(1/x.to_f)
end
def asech x
acosh(1/x.to_f)
end
def cot x
1/tan(x)
end
def coth x
1/atanh(x)
end
def acot x
atan(1/x.to_f)
end
def acoth x
atanh(1/x.to_f)
end
# Statistics
def covariance(x,y,*ranks)
x = NArray.to_na(x) unless x.kind_of?(NArray)
x = x.to_f if x.integer?
y = NArray.to_na(y) unless y.kind_of?(NArray)
y = y.to_f if y.integer?
n = x.rank_total(*ranks)
xm = x.accum(*ranks).div!(n)
ym = y.accum(*ranks).div!(n)
((x-xm)*(y-ym)).sum(*ranks) / (n-1)
end
module_function :csc,:sec,:cot,:csch,:sech,:coth
module_function :acsc,:asec,:acot,:acsch,:asech,:acoth
module_function :covariance
end
module FFTW
def convol(a1,a2)
n1x,n1y = a1.shape
n2x,n2y = a2.shape
raise "arrays must have same shape" if n1x!=n2x || n1y!=n2y
(FFTW.fftw( FFTW.fftw(a1,-1) * FFTW.fftw(a2,-1), 1).real) / (n1x*n1y)
end
module_function :convol
end
require 'nmatrix'
syntax highlighted by Code2HTML, v. 0.9.1