include Math

class NArray < Array

# NArray -- Numeric Array
# 1999/08/31-  T. Horinouchi
# 
# Super class: Array
#
# class methods
#
#   NArray.from_a(array)                   Array->NArray
#
#   NArray.indgen(len,iniv=0,incrememt=1)  index generator (NArray creation
#                                          with length len, and span_fill)
#
# methods Extention/Redefinition
#
#   to_a                          :    into Array class
#
#   (operators) + - * / **        :    Numeric definitions
#
#   span_fill([iniv[,increment]])  :   fill with iniv+increment*[0,1,2,..]
#
#   abs
#
#   sin cos tan exp log log10 sqrt ldexp atan2  :  from Math module
#                         No remedy for invalid inputs such as negative values
#                         for sqrt.

  def NArray.from_a(ar)
    # Array->NArray (no content check)
    out=NArray.new(ar.length)
    out[0..-1]=ar
    return out
  end

  def NArray.indgen(len,iniv=0,increment=1)
    out=NArray.new(len)
    out.span_fill(iniv,increment)
    return out
  end

  def to_a
    out=Array.new(self.length)
    out[0..-1]=self
    return out
  end

  def span_fill(iniv=0,increment=1)
    # fill linearly varying values starting at INIV with INCREMENT
    for i in 0..self.length-1
      self[i]=iniv+increment*i
    end
  end

  def +(other)
    out=self.dup
    if other.is_a?(Array) then
      if other.length < self.length then; raise(RuntimeError,"size of the operand is too short");end
      for i in 0..self.length-1
	out[i]=self[i]+other[i]
      end
    elsif other.is_a?(Numeric)
      for i in 0..self.length-1
	out[i]=self[i]+other
      end
    else
      raise(RuntimeError,"invalid type of the operand: "+other.type.to_s)
    end
    return out
  end
  #def (other)+
  #  out=self.dup
  #  for i in 0..self.length-1
  #    out[i]=other+self[i]
  #  end
  #  return out
  #end
  def -(other)
    out=self.dup
    if other.is_a?(Array) then
      if other.length < self.length then; raise(RuntimeError,"size of the operand is too short");end
      for i in 0..self.length-1
	out[i]=self[i]-other[i]
      end
    elsif other.is_a?(Numeric)
      for i in 0..self.length-1
	out[i]=self[i]-other
      end
    else
      raise(RuntimeError,"invalid type of the operand: "+other.type.to_s)
    end
    return out
  end
  def *(other)
    out=self.dup
    if other.is_a?(Array) then
      if other.length < self.length then; raise(RuntimeError,"size of the operand is too short");end
      for i in 0..self.length-1
	out[i]=self[i]*other[i]
      end
    elsif other.is_a?(Numeric)
      for i in 0..self.length-1
	out[i]=self[i]*other
      end
    else
      raise(RuntimeError,"invalid type of the operand: "+other.type.to_s)
    end
    return out
  end
  def /(other)
    out=self.dup
    if other.is_a?(Array) then
      if other.length < self.length then; raise(RuntimeError,"size of the operand is too short");end
      for i in 0..self.length-1
	out[i]=self[i]/other[i]
      end
    elsif other.is_a?(Numeric)
      for i in 0..self.length-1
	out[i]=self[i]/other
      end
    else
      raise(RuntimeError,"invalid type of the operand: "+other.type.to_s)
    end
    return out
  end

  def +@
    return self.dup
  end
  def -@
    out=self.dup
    for i in 0..self.length-1
      out[i]=-self[i]
    end
    return out
  end

  def **(num)
    out=self.dup
    if num.is_a?(Numeric)
      for i in 0..self.length-1
	out[i]=self[i]**num
      end
    else
      raise(RuntimeError,"invalid type of the operand: "+num.type.to_s)
    end
    return out
  end

  def abs
    out=self.dup
    for i in 0..self.length-1
      out[i]=self[i].abs
    end
    return out
  end


  ### from Math module ###
  def sin
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.sin(self[i]); end
    return out
  end
  def cos
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.cos(self[i]); end
    return out
  end
  def tan
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.tan(self[i]); end
    return out
  end
  def exp
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.exp(self[i]); end
    return out
  end
  def log
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.log(self[i]); end
    return out
  end
  def log10
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.log10(self[i]); end
    return out
  end
  def sqrt
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.sqrt(self[i]); end
    return out
  end
  def ldexp(exp)
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.ldexp(self[i],exp); end
    return out
  end
  def atan2(y)
    # atan2(self,y) = atan(self/y)
    out=self.dup
    for i in 0..self.length-1; out[i]=Math.atan2(self[i],y[i]); end
    return out
  end

end

## test for develeopment ##
#a=NArray.new(3)
#p a.length
#for i in 0..2; a[i]=i+1; end
#p a
#b=a+a
#p b
#b=a*10
#p b
#b=a**4
#p b
#b=-a
#p b

