lib/nmatrix/nvector.rb in nmatrix-0.0.4 vs lib/nmatrix/nvector.rb in nmatrix-0.0.5
- old
+ new
@@ -26,155 +26,236 @@
# This file defines the NVector class.
#++
# This is a specific type of NMatrix in which only one dimension is not 1.
# Although it is stored as a dim-2, n x 1, matrix, it acts as a dim-1 vector
-# of size n. If the @orientation flag is set to :row, it is stored as 1 x n
-# instead of n x 1.
+# of size n. If the @orientation flag is set to :column, it is stored as n x 1
+# instead of 1 x n.
class NVector < NMatrix
#
# call-seq:
- # new(length) -> NVector
- # new(length, values) -> NVector
- # new(length, values, dtype) -> NVector
+ # new(shape) -> NVector
+ # new(stype, shape) -> NVector
+ # new(shape, init) -> NVector
+ # new(:dense, shape, init) -> NVector
+ # new(:list, shape, init) -> NVector
+ # new(shape, init, dtype) -> NVector
+ # new(stype, shape, init, dtype) -> NVector
+ # new(stype, shape, dtype) -> NVector
#
- # Creates a new NVector.
+ # Creates a new NVector. See also NMatrix#initialize for a more detailed explanation of
+ # the arguments.
#
# * *Arguments* :
- # - +length+ -> Size of the vector.
- # - +values+ -> (optional) Initial values of the vector. Default is 0.
- # - +dtype+ -> (optional) Default is a guess from the +values+.
+ # - +stype+ -> (optional) Storage type of the vector (:list, :dense, :yale). Defaults to :dense.
+ # - +shape+ -> Shape of the vector. Accepts [n,1], [1,n], or n, where n is a Fixnum.
+ # - +init+ -> (optional) Yale: capacity; List: default value (0); Dense: initial value or values (uninitialized by default).
+ # - +dtype+ -> (optional if +init+ provided) Data type stored in the vector. For :dense and :list, can be inferred from +init+.
# * *Returns* :
# -
#
- def initialize(length, *args)
- super(:dense, [length, 1], *args)
- orientation
+ def initialize(*args)
+ stype = args[0].is_a?(Symbol) ? args.shift : :dense
+ shape = args[0].is_a?(Array) ? args.shift : [1,args.shift]
+
+ if shape.size != 2 || !shape.include?(1) || shape == [1,1]
+ raise(ArgumentError, "shape must be a Fixnum or an Array of positive Fixnums where exactly one value is 1")
+ end
+
+ super(stype, shape, *args)
end
+
#
# call-seq:
# orientation -> Symbol
#
- # Orientation defaults to column (e.g., [3,1] is a column of length 3). It
- # may also be row, e.g., for [1,5].
+ # Orientation defaults to row (e.g., [1,3] is a row of length 3). It
+ # may also be column, e.g., for [5,1].
#
def orientation
- @orientation ||= :column
+ shape[0] == 1 ? :row : :column
end
+ # Override NMatrix#each_row and #each_column
+ def each_column(get_by=:reference, &block) #:nodoc:
+ shape[0] == 1 ? self.each(&block) : (yield self)
+ end
+ def each_row(get_by=:reference, &block) #:nodoc:
+ shape[0] == 1 ? (yield self) : self.each(&block)
+ end
+
+
+
#
# call-seq:
- # transpose -> NVector
+ # vector[index] -> element
+ # vector[range] -> NVector
#
- # Returns a transposed copy of the vector.
+ # Retrieves an element or return a slice.
#
- # * *Returns* :
- # - NVector containing the transposed vector.
+ # Examples:
#
- def transpose
- t = super()
- t.flip!
+ # u = NVector.new(3, [10, 20, 30])
+ # u[0] # => 10
+ # u[0] + u[1] # => 30
+ # u[0 .. 1].shape # => [2, 1]
+ #
+ def [](i)
+ shape[0] == 1 ? super(0, i) : super(i, 0)
end
#
# call-seq:
- # transpose! -> NVector
+ # vector[index] = obj -> obj
#
- # Transpose the vector in-place.
+ # Stores +value+ at position +index+.
#
- # * *Returns* :
- # - NVector containing the transposed vector.
- #
- def transpose!
- super()
- self.flip!
+ def []=(i, val)
+ shape[0] == 1 ? super(0, i, val) : super(i, 0, val)
end
#
# call-seq:
- # multiply(m) ->
+ # dim -> 1
#
- # ...
+ # Returns the dimension of a vector, which is 1.
#
- # * *Arguments* :
- # - ++ ->
- # * *Returns* :
- # -
+ def dim; 1; end
+
#
- def multiply(m)
- t = super(m)
- t.flip!
+ # call-seq:
+ # size -> Fixnum
+ #
+ # Shorthand for the dominant shape component
+ def size
+ shape[0] > 1 ? shape[0] : shape[1]
end
#
# call-seq:
- # multiply!(m) ->
+ # max -> Numeric
#
- # ...
+ # Return the maximum element.
+ def max
+ max_so_far = self[0]
+ self.each do |x|
+ max_so_far = x if x > max_so_far
+ end
+ max_so_far
+ end
+
#
- # * *Arguments* :
- # - ++ ->
- # * *Returns* :
- # -
+ # call-seq:
+ # min -> Numeric
#
- def multiply!(m)
- super().flip!
+ # Return the minimum element.
+ def min
+ min_so_far = self[0]
+ self.each do |x|
+ min_so_far = x if x < min_so_far
+ end
+ min_so_far
end
#
# call-seq:
- # vector[index] -> element
- # vector[range] -> NVector
+ # absolute_sum -> Numeric
#
- # Retrieves an element or return a slice.
+ # == Arguments
+ # - +incx+ -> the skip size (defaults to 1, no skip)
+ # - +n+ -> the number of elements to include
#
- # Examples:
+ # Return the sum of the contents of the vector. This is the BLAS asum routine.
+ def asum incx=1, n=nil
+ NMatrix::BLAS::asum(self, incx, self.size / incx)
+ end
+ alias :absolute_sum :asum
+
#
- # u = NVector.new(3, [10, 20, 30])
- # u[0] # => 10
- # u[0] + u[1] # => 30
- # u[0 .. 1].shape # => [2, 1]
+ # call-seq:
+ # norm2 -> Numeric
#
- def [](i)
- case @orientation
- when :column; super(i, 0)
- when :row; super(0, i)
+ # == Arguments
+ # - +incx+ -> the skip size (defaults to 1, no skip)
+ # - +n+ -> the number of elements to include
+ #
+ # Return the 2-norm of the vector. This is the BLAS nrm2 routine.
+ def nrm2 incx=1, n=nil
+ NMatrix::BLAS::nrm2(self, incx, self.size / incx)
+ end
+ alias :norm2 :nrm2
+
+ #
+ # call-seq:
+ # to_a -> Array
+ #
+ # Converts the NVector to a regular Ruby Array.
+ def to_a
+ if self.stype == :dense
+ ary = Array.new(size)
+ self.each.with_index { |v,idx| ary[idx] = v }
+ else
+ begin
+ ary = Array.new(size, self[0] - self[0]) # Fill the Array with 0s of the appropriate class
+ rescue NoMethodError # handle Ruby Object arrays that might have nils instead of 0s
+ ary = Array.new(size)
+ end
+ self.each_stored_with_index { |v,idx| ary[idx] = v }
end
+ ary
end
#
# call-seq:
- # vector[index] = obj -> obj
+ # each_stored_with_index -> Enumerator
#
- # Stores +value+ at position +index+.
+ # Allow iteration across an NVector's stored values. See also NMatrix#each_stored_with_indices
#
- def []=(i, val)
- case @orientation
- when :column; super(i, 0, val)
- when :row; super(0, i, val)
+ def each_stored_with_index(&block)
+ return enum_for(:each_stored_with_index) unless block_given?
+ self.each_stored_with_indices do |v, i, j|
+ shape[0] == 1 ? yield(v,j) : yield(v,i)
end
+ self
end
#
# call-seq:
- # dim -> 1
+ # shuffle! -> ...
+ # shuffle!(random: rng) -> ...
#
- # Returns the dimension of a vector, which is 1.
+ # Re-arranges the contents of an NVector.
#
- def dim; 1; end
+ # TODO: Write more efficient version for Yale, list.
+ def shuffle!(*args)
+ ary = self.to_a
+ ary.shuffle!(*args)
+ ary.each.with_index { |v,idx| self[idx] = v }
+ self
+ end
- # shorthand for the dominant shape component
- def size
- shape[0] > 1 ? shape[0] : shape[1]
+
+ #
+ # call-seq:
+ # shuffle -> ...
+ # shuffle(rng) -> ...
+ #
+ # Re-arranges the contents of an NVector.
+ #
+ # TODO: Write more efficient version for Yale, list.
+ def shuffle(*args)
+ t = self.clone
+ t.shuffle!(*args)
end
+
# TODO: Make this actually pretty.
def pretty_print(q = nil) #:nodoc:
- dim = @orientation == :row ? 1 : 0
+ dimen = shape[0] == 1 ? 1 : 0
- arr = (0...shape[dim]).inject(Array.new){ |a, i| a << self[i] }
+ arr = (0...shape[dimen]).inject(Array.new){ |a, i| a << self[i] }
if q.nil?
puts "[" + arr.join("\n") + "]"
else
q.group(1, "", "\n") do
@@ -184,29 +265,9 @@
end
def inspect #:nodoc:
original_inspect = super()
original_inspect = original_inspect[0...original_inspect.size-1]
- original_inspect.gsub("@orientation=:#{self.orientation}", "orientation:#{self.orientation}") + ">"
+ original_inspect += " orientation:#{self.orientation}>"
end
-protected
-# def inspect_helper #:nodoc:
-# x = (super() << "orientation:#{self.orientation}") #.gsub(" @orientation=:#{self.orientation}", "")
-# binding.pry
-# x
-# end
-
- #
- # call-seq:
- # flip_orientation! -> NVector
- #
- # Flip the orientation of the vector.
- #
- # * *Returns* :
- # - NVector with orientation changed.
- #
- def flip_orientation!
- returning(self) { @orientation = @orientation == :row ? :column : :row }
- end
- alias :flip! :flip_orientation!
end