lib/nmatrix/shortcuts.rb in nmatrix-0.1.0 vs lib/nmatrix/shortcuts.rb in nmatrix-0.2.0

- old
+ new

@@ -57,11 +57,10 @@ # NMatrix[Numeric, ..., Numeric, dtype: Symbol] -> NMatrix # NMatrix[Array, dtype: Symbol] -> NMatrix # # The default value for +dtype+ is guessed from the first parameter. For example: # NMatrix[1.0, 2.0].dtype # => :float64 - # NMatrix[1r, 2r].dtype # => :rational64 # # But this is just a *guess*. If the other values can't be converted to # this dtype, a +TypeError+ will be raised. # # You can use the +N+ constant in this way: @@ -273,21 +272,90 @@ m end alias :diag :diagonal alias :diagonals :diagonal + # Generate a block-diagonal NMatrix from the supplied 2D square matrices. + # + # * *Arguments* + # - +*params+ -> An array that collects all arguments passed to the method. The method + # can receive any number of arguments. Optionally, the last entry of +params+ is + # a hash of options from NMatrix#initialize. All other entries of +params+ are + # the blocks of the desired block-diagonal matrix. Each such matrix block can be + # supplied as a square 2D NMatrix object, or alternatively as an array of arrays + # (with dimensions corresponding to a square matrix), or alternatively as a number. + # * *Returns* + # - NMatrix of block-diagonal form filled with specified matrices + # as the blocks along the diagonal. + # + # * *Example* + # + # a = NMatrix.new([2,2], [1,2,3,4]) + # b = NMatrix.new([1,1], [123], dtype: :float64) + # c = Array.new(2) { [[10,10], [10,10]] } + # d = Array[[1,2,3], [4,5,6], [7,8,9]] + # m = NMatrix.block_diagonal(a, b, *c, d, 10.0, 11, dtype: :int64, stype: :yale) + # => + # [ + # [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + # [3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + # [0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0] + # [0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0] + # [0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0] + # [0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0] + # [0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0] + # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11] + # ] + # + def block_diagonal(*params) + options = params.last.is_a?(Hash) ? params.pop : {} + params.each_index do |i| + params[i] = params[i].to_nm if params[i].is_a?(Array) # Convert Array to NMatrix + params[i] = NMatrix.new([1,1], [params[i]]) if params[i].is_a?(Numeric) # Convert number to NMatrix + end + + block_sizes = [] #holds the size of each matrix block + params.each do |b| + unless b.is_a?(NMatrix) + raise(ArgumentError, "Only NMatrix or appropriate Array objects or single numbers allowed") + end + raise(ArgumentError, "Only 2D matrices or 2D arrays allowed") unless b.shape.size == 2 + raise(ArgumentError, "Only square-shaped blocks allowed") unless b.shape[0] == b.shape[1] + block_sizes << b.shape[0] + end + + block_diag_mat = NMatrix.zeros(block_sizes.sum, options) + (0...params.length).each do |n| + # First determine the size and position of the n'th block in the block-diagonal matrix + block_size = block_sizes[n] + block_pos = block_sizes[0...n].sum + # populate the n'th block in the block-diagonal matrix + (0...block_size).each do |i| + (0...block_size).each do |j| + block_diag_mat[block_pos+i,block_pos+j] = params[n][i,j] + end + end + end + + return block_diag_mat + end + alias :block_diag :block_diagonal + # # call-seq: # random(shape) -> NMatrix # # Creates a +:dense+ NMatrix with random numbers between 0 and 1 generated # by +Random::rand+. The parameter is the dimension of the matrix. # # If you use an integer dtype, make sure to specify :scale as a parameter, or you'll - # only get a matrix of 0s. You may not currently generate random numbers for - # a rational matrix. + # only get a matrix of 0s. # # * *Arguments* : # - +shape+ -> Array (or integer for square matrix) specifying the dimensions. # * *Returns* : # - NMatrix filled with random values. @@ -300,12 +368,10 @@ # NMatrix.random([2, 2], :dtype => :byte, :scale => 255) # => [ [252, 108] [44, 12] ] # def random(shape, opts={}) scale = opts.delete(:scale) || 1.0 - raise(NotImplementedError, "does not support rational random number generation") if opts[:dtype].to_s =~ /^rational/ - rng = Random.new random_values = [] @@ -328,11 +394,10 @@ # indgen(shape) -> NMatrix of :int64 # findgen(shape) -> NMatrix of :float32 # dindgen(shape) -> NMatrix of :float64 # cindgen(shape) -> NMatrix of :complex64 # zindgen(shape) -> NMatrix of :complex128 - # rindgen(shape) -> NMatrix of :rational128 # rbindgen(shape) -> NMatrix of :object # # Creates a matrix filled with a sequence of integers starting at zero. # # * *Arguments* : @@ -359,10 +424,10 @@ NMatrix.new(shape, values, {:stype => :dense}.merge(options)) end {:bindgen => :byte, :indgen => :int64, :findgen => :float32, :dindgen => :float64, :cindgen => :complex64, :zindgen => :complex128, - :rindgen => :rational128, :rbindgen => :object}.each_pair do |meth, dtype| + :rbindgen => :object}.each_pair do |meth, dtype| define_method(meth) { |shape| NMatrix.seq(shape, :dtype => dtype) } end end end