rmatrix 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rmatrix/core.rb +1 -0
- data/lib/rmatrix/indices.rb +69 -8
- data/lib/rmatrix/matrix.rb +71 -30
- data/lib/rmatrix/matrix_table.rb +83 -0
- data/lib/rmatrix/print_table.rb +107 -0
- data/lib/rmatrix/version.rb +1 -1
- data/rmatrix.todo +6 -2
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 66edec4fe60372252f4542b6c2adf5e7ff88349e
         | 
| 4 | 
            +
              data.tar.gz: 363d633958bce93fb9ae62de0aa8d12ba1c441bc
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: cadab96ed60b3bc2912abe69502ef76ed8739a15834fe32938188b1a011e1906b2e10334f7d79853761263f494e842390bf4a28af7e47cafa35392fc330d8c36
         | 
| 7 | 
            +
              data.tar.gz: 7d6ba92b3df5794e9a315d788b994b454825d54745dd93c62c987a2547d1288976be17ab63ebb3a73b871da0ca4b5a1d22e2e52f04152c802a2728b11bb008c5
         | 
    
        data/lib/rmatrix/core.rb
    CHANGED
    
    
    
        data/lib/rmatrix/indices.rb
    CHANGED
    
    | @@ -1,17 +1,74 @@ | |
| 1 1 | 
             
            module RMatrix
         | 
| 2 2 | 
             
              module Indices
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def []=(*args, value)
         | 
| 5 | 
            +
                  indices = unmap_args(args)
         | 
| 6 | 
            +
                  raw[*indices] = value
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 3 9 | 
             
                def [](*args)
         | 
| 4 10 | 
             
                  indices           = unmap_args(args)
         | 
| 5 11 | 
             
                  result_row_map    = build_result_map(self.row_map, indices.first, self.rows)      if self.row_map
         | 
| 6 12 | 
             
                  result_column_map = build_result_map(self.column_map, indices.last, self.columns) if self.column_map
         | 
| 7 | 
            -
             | 
| 13 | 
            +
             | 
| 14 | 
            +
                  row_indices, column_indices = indices
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  result_column_label_map = nil
         | 
| 17 | 
            +
                  result_row_label_map = nil
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  if row_label_map
         | 
| 20 | 
            +
                    case row_indices
         | 
| 21 | 
            +
                    when true then result_row_label_map = row_label_map
         | 
| 22 | 
            +
                    else
         | 
| 23 | 
            +
                      result_row_label_map = walk_indices(row_indices, row_label_map).each_slice(2).to_h
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  if column_label_map
         | 
| 28 | 
            +
                    case column_indices
         | 
| 29 | 
            +
                    when true then result_column_label_map = column_label_map
         | 
| 30 | 
            +
                    else
         | 
| 31 | 
            +
                      result_column_label_map = walk_indices(column_indices, column_label_map).each_slice(2).to_h
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  raw[*indices, column_map: result_column_map, column_label_map: result_column_label_map, row_map: result_row_map, row_label_map: result_row_label_map]
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def method_missing(name, *args, &block)
         | 
| 39 | 
            +
                  if row_map && row_map.include?(name)
         | 
| 40 | 
            +
                    self[name, true]
         | 
| 41 | 
            +
                  elsif column_map && column_map.include?(name)
         | 
| 42 | 
            +
                    self[true, name]
         | 
| 43 | 
            +
                  else
         | 
| 44 | 
            +
                    super
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def walk_indices(indices, parent, i={index: 0})
         | 
| 49 | 
            +
                  Array(indices).flat_map do |index|
         | 
| 50 | 
            +
                    res = case index
         | 
| 51 | 
            +
                    when Array, Range then walk_indices(index.to_a, parent, i)
         | 
| 52 | 
            +
                    else [i[:index], parent[index]]
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                    i[:index] += 1
         | 
| 55 | 
            +
                    res
         | 
| 56 | 
            +
                  end
         | 
| 8 57 | 
             
                end
         | 
| 9 58 |  | 
| 10 59 | 
             
                def raw
         | 
| 11 60 | 
             
                  @raw ||= begin
         | 
| 12 61 | 
             
                    raw = Struct.new(:narray, :typecode).new(self.narray, self.typecode)
         | 
| 13 | 
            -
                    def raw.[](*args, column_map: nil, row_map: nil)
         | 
| 14 | 
            -
                       | 
| 62 | 
            +
                    def raw.[](*args, column_map: nil, row_map: nil, row_label_map: nil, column_label_map: nil)
         | 
| 63 | 
            +
                      begin
         | 
| 64 | 
            +
                        args.all?{|x| Fixnum === x } ? narray[*args.reverse] : Matrix.new(narray[*args.reverse], typecode, column_map: column_map, row_map: row_map, row_label_map: row_label_map, column_label_map: column_label_map)
         | 
| 65 | 
            +
                      rescue StandardError => e
         | 
| 66 | 
            +
                        raise IndexError.new("Error accessing index at #{args}. Shape is #{narray.shape.reverse}")
         | 
| 67 | 
            +
                      end
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    def raw.[]=(*args, value)
         | 
| 71 | 
            +
                      narray[*args.reverse] = value
         | 
| 15 72 | 
             
                    end
         | 
| 16 73 | 
             
                    raw
         | 
| 17 74 | 
             
                  end
         | 
| @@ -66,16 +123,19 @@ module RMatrix | |
| 66 123 | 
             
                def unmap_args(args)
         | 
| 67 124 | 
             
                  if args.length == 1
         | 
| 68 125 | 
             
                    if row_map
         | 
| 69 | 
            -
                      return [unmap_index(self.row_map, args[0]), true] rescue nil
         | 
| 126 | 
            +
                      return [Array(unmap_index(self.row_map, args[0])), true] rescue nil
         | 
| 70 127 | 
             
                    end
         | 
| 71 128 | 
             
                    if column_map
         | 
| 72 | 
            -
                      return [true,  | 
| 129 | 
            +
                      return [true, Array(unmap_index(self.column_map, args[0]))] rescue nil
         | 
| 73 130 | 
             
                    end
         | 
| 74 131 | 
             
                    return [args[0]]
         | 
| 75 132 | 
             
                  else
         | 
| 133 | 
            +
                    row_index    = self.row_map ? unmap_index(self.row_map, args[0]) : args[0]
         | 
| 134 | 
            +
                    column_index = self.column_map ? unmap_index(self.column_map, args[1]) : args[1]
         | 
| 135 | 
            +
                    column_index = [column_index] if column_index.kind_of?(Fixnum)
         | 
| 76 136 | 
             
                    [
         | 
| 77 | 
            -
                       | 
| 78 | 
            -
                       | 
| 137 | 
            +
                      row_index,
         | 
| 138 | 
            +
                      column_index
         | 
| 79 139 | 
             
                    ]
         | 
| 80 140 | 
             
                  end
         | 
| 81 141 | 
             
                end
         | 
| @@ -98,7 +158,8 @@ module RMatrix | |
| 98 158 | 
             
                      first..last
         | 
| 99 159 | 
             
                    end
         | 
| 100 160 | 
             
                  else
         | 
| 101 | 
            -
                    index = map[columns]
         | 
| 161 | 
            +
                    index = (map[columns] rescue nil)
         | 
| 162 | 
            +
                    index = columns if !index && columns.kind_of?(Fixnum)
         | 
| 102 163 | 
             
                    raise "Value not present in index mapping: #{columns}" unless index
         | 
| 103 164 | 
             
                    index
         | 
| 104 165 | 
             
                  end
         | 
    
        data/lib/rmatrix/matrix.rb
    CHANGED
    
    | @@ -1,26 +1,51 @@ | |
| 1 1 | 
             
            module RMatrix
         | 
| 2 2 | 
             
              class Matrix
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                class << self
         | 
| 5 | 
            +
                  attr_accessor :named_inspect
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 3 8 | 
             
                require 'narray'
         | 
| 4 9 | 
             
                require_relative 'typecode'
         | 
| 5 10 |  | 
| 6 11 | 
             
                include Enumerable
         | 
| 7 12 | 
             
                include Indices
         | 
| 8 13 |  | 
| 9 | 
            -
                attr_accessor :invert_next_operation, :narray, :typecode, :row_map, :column_map
         | 
| 14 | 
            +
                attr_accessor :invert_next_operation, :narray, :typecode, :row_map, :column_map, :row_label_map, :column_label_map
         | 
| 10 15 | 
             
                attr_writer :matrix
         | 
| 11 16 |  | 
| 12 | 
            -
                def initialize(source, typecode=Typecode::FLOAT, column_map: nil, row_map: nil)
         | 
| 13 | 
            -
                  self.typecode | 
| 14 | 
            -
                  self.narray | 
| 15 | 
            -
                  self.row_map | 
| 17 | 
            +
                def initialize(source, typecode=Typecode::FLOAT, column_map: nil, row_map: nil, column_label_map: nil, row_label_map: nil)
         | 
| 18 | 
            +
                  self.typecode    = typecode
         | 
| 19 | 
            +
                  self.narray      = two_dimensional(source, typecode)
         | 
| 20 | 
            +
                  self.row_map     = row_map
         | 
| 21 | 
            +
                  self.column_map  = column_map
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def row_map=(row_map)
         | 
| 25 | 
            +
                  @row_map = parse_map(row_map)
         | 
| 26 | 
            +
                  @row_label_map = @row_map.invert unless !@row_map || @row_map.default_proc
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def column_map=(column_map)
         | 
| 30 | 
            +
                  @column_map = parse_map(column_map)
         | 
| 31 | 
            +
                  @column_label_map = @column_map.invert unless !@column_map || @column_map.default_proc
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def parse_map(map, invert: false)
         | 
| 35 | 
            +
                  case map
         | 
| 36 | 
            +
                  when nil then map
         | 
| 37 | 
            +
                  when Array then invert ? map.each.with_index.map.to_h.invert : map.each.with_index.map.to_h
         | 
| 38 | 
            +
                  when Hash then map
         | 
| 39 | 
            +
                  else raise 'Invalid map type encountered'
         | 
| 40 | 
            +
                  end
         | 
| 16 41 | 
             
                end
         | 
| 17 42 |  | 
| 18 43 | 
             
                def matrix
         | 
| 19 44 | 
             
                  @matrix ||= narray.empty? ? narray : NMatrix.refer(narray)
         | 
| 20 45 | 
             
                end
         | 
| 21 46 |  | 
| 22 | 
            -
                def self.blank(rows: 1, columns: 1, typecode: Typecode::FLOAT, initial: 0)
         | 
| 23 | 
            -
                  source = self.new(NArray.new(typecode, columns, rows), typecode)
         | 
| 47 | 
            +
                def self.blank(rows: 1, columns: 1, typecode: Typecode::FLOAT, initial: 0, column_map: nil, row_map: nil)
         | 
| 48 | 
            +
                  source = self.new(NArray.new(typecode, columns, rows), typecode, column_map: column_map, row_map: row_map)
         | 
| 24 49 | 
             
                  source.narray[]= initial unless source.empty?
         | 
| 25 50 | 
             
                  source
         | 
| 26 51 | 
             
                end
         | 
| @@ -30,7 +55,7 @@ module RMatrix | |
| 30 55 | 
             
                end
         | 
| 31 56 |  | 
| 32 57 | 
             
                def _dump(level)
         | 
| 33 | 
            -
             | 
| 58 | 
            +
                  narray.to_s << ':' << columns.to_s << ':' << rows.to_s << ':' << narray.typecode.to_s
         | 
| 34 59 | 
             
                end
         | 
| 35 60 |  | 
| 36 61 | 
             
                def self._load arg
         | 
| @@ -280,28 +305,43 @@ module RMatrix | |
| 280 305 | 
             
                end
         | 
| 281 306 |  | 
| 282 307 | 
             
                def to_significant_figures(x, p)
         | 
| 283 | 
            -
                  x. | 
| 284 | 
            -
                    nm = Math.log(x, 10.0).floor + 1.0 - p
         | 
| 285 | 
            -
                    (((10.0 ** -nm) * x).round * (10.0 ** nm)).round(nm.abs)
         | 
| 286 | 
            -
                  end
         | 
| 308 | 
            +
                  ("%-.#{p}e" % x).gsub(/0+e/,'e').gsub('.e+00','').gsub('e+00','')
         | 
| 287 309 | 
             
                end
         | 
| 288 310 |  | 
| 289 | 
            -
                def inspect(sz | 
| 290 | 
            -
                   | 
| 291 | 
            -
                   | 
| 292 | 
            -
                   | 
| 293 | 
            -
                   | 
| 294 | 
            -
                   | 
| 295 | 
            -
                  values = values.map{|line| line.map{|val| val.rjust(max_width, ' ') }}
         | 
| 296 | 
            -
                  "#{rows} x #{columns} Matrix\nM[#{values.map{|row| "[#{row.join(", ")}]" }.join(",\n  ")}"
         | 
| 311 | 
            +
                def inspect(sz: 10, sig: 6, names: RMatrix::Matrix.named_inspect)
         | 
| 312 | 
            +
                  desc = case
         | 
| 313 | 
            +
                  when self.is_vector? then "Vector(#{self.length})"
         | 
| 314 | 
            +
                  else "Matrix(#{rows} x #{columns})"
         | 
| 315 | 
            +
                  end
         | 
| 316 | 
            +
                  "#{desc}\n#{RMatrix::MatrixTable.new(self).to_s}"
         | 
| 297 317 | 
             
                end
         | 
| 298 318 |  | 
| 299 319 | 
             
                def to_tex(sz = 10, sig=6)
         | 
| 300 320 | 
             
                  values = condensed(sz, sig)
         | 
| 321 | 
            +
                  column_headers = column_label_map ? values[0].map.with_index do |v, i|
         | 
| 322 | 
            +
                    case v
         | 
| 323 | 
            +
                    when '\\cdots' then '\\cdots'
         | 
| 324 | 
            +
                    else (column_label_map && column_label_map[i]) || i
         | 
| 325 | 
            +
                    end
         | 
| 326 | 
            +
                  end : []
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                  row_headers = row_label_map ? values.map.with_index do |v, i|
         | 
| 329 | 
            +
                    case v[0]
         | 
| 330 | 
            +
                    when '\\vdots' then '\\vdots'
         | 
| 331 | 
            +
                    else (row_label_map && row_label_map[i]) || i
         | 
| 332 | 
            +
                    end
         | 
| 333 | 
            +
                  end : []
         | 
| 334 | 
            +
             | 
| 301 335 | 
             
                  <<-TEX
         | 
| 302 | 
            -
             | 
| 303 | 
            -
             | 
| 304 | 
            -
            \\end{ | 
| 336 | 
            +
            $
         | 
| 337 | 
            +
            \\begin{array}{c} &
         | 
| 338 | 
            +
            \\begin{array}{c} #{column_headers.join(" & ")} \\end{array}\\\\
         | 
| 339 | 
            +
            \\begin{array}{c} #{row_headers.join(" \\\\ ")} \\end{array} &
         | 
| 340 | 
            +
              \\left(\\begin{array}{ccc}
         | 
| 341 | 
            +
                #{values.map{|line| line.join(" & ")}.join(" \\\\ ")}
         | 
| 342 | 
            +
              \\end{array}\\right)
         | 
| 343 | 
            +
            \\end{array}
         | 
| 344 | 
            +
            $
         | 
| 305 345 | 
             
            TEX
         | 
| 306 346 | 
             
                end
         | 
| 307 347 |  | 
| @@ -333,21 +373,21 @@ TEX | |
| 333 373 | 
             
                  blank.narray.to_a.map{|line| (sig ? Array(line).map{|v| Numeric === v ? to_significant_figures(v,sig) : v } : Array(line))}
         | 
| 334 374 | 
             
                end
         | 
| 335 375 |  | 
| 336 | 
            -
                def transpose
         | 
| 337 | 
            -
                  Matrix.new(self.matrix.transpose, typecode)
         | 
| 376 | 
            +
                def transpose()
         | 
| 377 | 
            +
                  Matrix.new(self.matrix.transpose, typecode, column_map: self.row_map, row_map: self.column_map, column_label_map: self.row_label_map, row_label_map: self.column_label_map)
         | 
| 338 378 | 
             
                end
         | 
| 339 379 |  | 
| 340 | 
            -
                def self.[](*inputs, typecode: Typecode::FLOAT, row_map: nil, column_map: nil)
         | 
| 380 | 
            +
                def self.[](*inputs, typecode: Typecode::FLOAT, row_map: nil, column_map: nil, column_label_map: nil, row_label_map: nil)
         | 
| 341 381 | 
             
                  if inputs.length == 1 && Matrix === inputs[0]
         | 
| 342 382 | 
             
                    inputs[0]
         | 
| 343 383 | 
             
                  elsif inputs.length == 1 && [String, Symbol].include?(inputs[0].class)
         | 
| 344 384 | 
             
                    if ['byte', 'sint', 'int', 'sfloat', 'float', 'scomplex', 'complex', 'object'].include?(inputs[0])
         | 
| 345 | 
            -
                      ->(*source){ Matrix.new(source, inputs[0], row_map: row_map, column_map: column_map)}
         | 
| 385 | 
            +
                      ->(*source){ Matrix.new(source, inputs[0], row_map: row_map, column_map: column_map, row_label_map: row_label_map, column_label_map: column_label_map)}
         | 
| 346 386 | 
             
                    else
         | 
| 347 | 
            -
                      Matrix.new(inputs[0], typecode, row_map: row_map, column_map: column_map)
         | 
| 387 | 
            +
                      Matrix.new(inputs[0], typecode, row_map: row_map, column_map: column_map, row_label_map: row_label_map, column_label_map: column_label_map)
         | 
| 348 388 | 
             
                    end
         | 
| 349 389 | 
             
                  else
         | 
| 350 | 
            -
                    Matrix.new(inputs, typecode, row_map: row_map, column_map: column_map)
         | 
| 390 | 
            +
                    Matrix.new(inputs, typecode, row_map: row_map, column_map: column_map, row_label_map: row_label_map, column_label_map: column_label_map)
         | 
| 351 391 | 
             
                  end
         | 
| 352 392 | 
             
                end
         | 
| 353 393 |  | 
| @@ -475,4 +515,5 @@ TEX | |
| 475 515 | 
             
              end
         | 
| 476 516 |  | 
| 477 517 | 
             
              class ::NArray; include Enumerable; end
         | 
| 478 | 
            -
            end
         | 
| 518 | 
            +
            end
         | 
| 519 | 
            +
            RMatrix::Matrix.named_inspect = true
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            module RMatrix
         | 
| 2 | 
            +
              class MatrixTable < PrintTable
         | 
| 3 | 
            +
                def initialize(matrix, max_columns: 10, max_rows: 10)
         | 
| 4 | 
            +
                  super()
         | 
| 5 | 
            +
                  column_offset, row_offset = 0, 0
         | 
| 6 | 
            +
                  column_labels = !!matrix.column_label_map
         | 
| 7 | 
            +
                  row_labels    = !!matrix.row_label_map
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  printed_rows = [matrix.rows, max_rows].min
         | 
| 10 | 
            +
                  printed_columns = [matrix.columns, max_columns].min
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  if matrix.column_label_map
         | 
| 13 | 
            +
                    printed_columns.times do |i|
         | 
| 14 | 
            +
                      column_label = matrix.column_label_map[i]
         | 
| 15 | 
            +
                      if column_label
         | 
| 16 | 
            +
                        self[i+1 + (row_labels ? 1 : 0 ), 0] = column_label.inspect
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                    row_offset += 1
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  if matrix.row_label_map
         | 
| 23 | 
            +
                    printed_rows.times do |i|
         | 
| 24 | 
            +
                      row_label = matrix.row_label_map[i]
         | 
| 25 | 
            +
                      if row_label
         | 
| 26 | 
            +
                        self[0, i + (column_labels ?  1 : 0)] = row_label.inspect
         | 
| 27 | 
            +
                      end
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                    column_offset += 1
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
             | 
| 33 | 
            +
                  self[column_offset,row_offset] = "#{matrix.is_vector? ? 'V' : 'M'}["
         | 
| 34 | 
            +
                  column_offset += 1
         | 
| 35 | 
            +
                  matrix.each_row.with_index do |row, row_idx|
         | 
| 36 | 
            +
                    break if row_idx > printed_rows
         | 
| 37 | 
            +
                    row.each.with_index do |cell, column_idx|
         | 
| 38 | 
            +
                      break if column_idx > printed_columns
         | 
| 39 | 
            +
                      self[column_idx + column_offset, row_idx + row_offset] = cell
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                    self[[matrix.columns + column_offset, printed_columns + column_offset + 1].min, row_idx + row_offset] = ',' if (row_idx + row_offset - 1) != printed_rows
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  column_overlap = matrix.columns > max_columns
         | 
| 45 | 
            +
                  row_overlap    = matrix.rows    > max_rows
         | 
| 46 | 
            +
                  both_overlap   = column_overlap && row_overlap
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  if column_overlap
         | 
| 49 | 
            +
                    printed_rows.times do |row|
         | 
| 50 | 
            +
                      self[max_columns + column_offset - 1, row + row_offset] = '…'
         | 
| 51 | 
            +
                      self[max_columns + column_offset, row + row_offset] = matrix[row, -1].first
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  if row_overlap
         | 
| 56 | 
            +
                    printed_columns.times do |column|
         | 
| 57 | 
            +
                      self[column + column_offset, max_rows + row_offset - 1] = '⋮'
         | 
| 58 | 
            +
                      self[column + column_offset, max_rows + row_offset] = matrix[column, -1].first
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  if both_overlap
         | 
| 63 | 
            +
                    self[printed_columns + column_offset - 1, printed_rows + row_offset - 1] = "⋱"
         | 
| 64 | 
            +
                    self[printed_columns + column_offset - 1, printed_rows + row_offset] = '⋮'
         | 
| 65 | 
            +
                    self[printed_columns + column_offset, printed_rows + row_offset - 1] = '…'
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  self[self.column_count - 1, self.row_count - 1] = ']'
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  if row_labels
         | 
| 71 | 
            +
                    self.set_column_separator( 0, ' ')
         | 
| 72 | 
            +
                    self.set_column_separator( 1, '[')
         | 
| 73 | 
            +
                    self.set_column_separator(self.column_count - 1, ']')
         | 
| 74 | 
            +
                  else
         | 
| 75 | 
            +
                    self.set_column_separator( 0, '[')
         | 
| 76 | 
            +
                    self.set_column_separator(self.column_count - 2, ']')
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  self.set_column_separator(self.column_count - 2, ']')
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            end
         | 
| @@ -0,0 +1,107 @@ | |
| 1 | 
            +
            module RMatrix
         | 
| 2 | 
            +
              class PrintTable
         | 
| 3 | 
            +
                attr_accessor :row_count, :column_count, :cells, :column_justifications, :separators
         | 
| 4 | 
            +
                def initialize
         | 
| 5 | 
            +
                  self.row_count = self.column_count = 0
         | 
| 6 | 
            +
                  self.cells = {}
         | 
| 7 | 
            +
                  self.column_justifications = {}
         | 
| 8 | 
            +
                  self.separators = Hash.new(', ')
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def to_s
         | 
| 12 | 
            +
                  widths = self.column_widths
         | 
| 13 | 
            +
                  self.row_count.times.map do |row|
         | 
| 14 | 
            +
                    self.column_count.times.flat_map do |column|
         | 
| 15 | 
            +
                      cell_text = cell_repr(self.cells[[column, row]])
         | 
| 16 | 
            +
                      justification = column_justification(column)
         | 
| 17 | 
            +
                      width = widths[column]
         | 
| 18 | 
            +
                      contents = case justification
         | 
| 19 | 
            +
                      when :left  then cell_text.ljust(width)
         | 
| 20 | 
            +
                      when :right then cell_text.rjust(width)
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                      [contents,self.separators[[column, row]]]
         | 
| 23 | 
            +
                    end[0...-1].join
         | 
| 24 | 
            +
                  end.join("\n")
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def to_tex
         | 
| 28 | 
            +
                  tex_map = self.row_count.times.map do |row|
         | 
| 29 | 
            +
                    self.column_count.times.map do |column|
         | 
| 30 | 
            +
                      cell_repr(self.cells[[column, row]])
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  <<-TEX
         | 
| 34 | 
            +
            \\[
         | 
| 35 | 
            +
              \\text{Mat}_{\\varphi\\text{ to }M} = \\kbordermatrix{
         | 
| 36 | 
            +
                & c_1 & c_2 & c_3 & c_4 & c_5 \\\\
         | 
| 37 | 
            +
                r_1 & 1 & 1 & 1 & 1 & 1 \\\\
         | 
| 38 | 
            +
                r_2 & 0 & 1 & 0 & 0 & 1 \\\\
         | 
| 39 | 
            +
                r_3 & 0 & 0 & 1 & 0 & 1 \\\\
         | 
| 40 | 
            +
                r_4 & 0 & 0 & 0 & 1 & 1 \\\\
         | 
| 41 | 
            +
                r_5 & 0 & 0 & 0 & 0 & 1
         | 
| 42 | 
            +
              }
         | 
| 43 | 
            +
            \\]
         | 
| 44 | 
            +
            TEX
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def column_justification(i)
         | 
| 48 | 
            +
                  case self.column_justifications[i]
         | 
| 49 | 
            +
                  when nil then :right
         | 
| 50 | 
            +
                  when :right then :right
         | 
| 51 | 
            +
                  when :left then :left
         | 
| 52 | 
            +
                  else raise "Unexpected justification for column #{self.column_justifications[i] }"
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def set_column_separator(column, separator)
         | 
| 57 | 
            +
                  self.row_count.times do |row|
         | 
| 58 | 
            +
                    self.separators[[column, row]] =  separator
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def column_widths
         | 
| 63 | 
            +
                  column_count.times.map do |i|
         | 
| 64 | 
            +
                    column_width(i)
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def column_width(column)
         | 
| 69 | 
            +
                  self.row_count.times.reduce(0) do |agg, row|
         | 
| 70 | 
            +
                    [agg, self.cell_repr(self.cells[[column, row]]).length].max
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def cell_repr(cell)
         | 
| 75 | 
            +
                  case cell
         | 
| 76 | 
            +
                  when nil then ''
         | 
| 77 | 
            +
                  when Numeric then numeric_to_truncated_string(cell)
         | 
| 78 | 
            +
                  else "#{cell}"
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def numeric_to_truncated_string(numeric)
         | 
| 83 | 
            +
                  ("%-.4e" % numeric).gsub(/(?<!\.)0+e/,'e').gsub('.e+00','').gsub('e+00','')
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                def [](column, row)
         | 
| 87 | 
            +
                  self.cells[[column, row]]
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def []=(column, row, value)
         | 
| 91 | 
            +
                  build_column!(column)
         | 
| 92 | 
            +
                  build_row!(row)
         | 
| 93 | 
            +
                  self.cells[[column, row]] = value
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def build_column!(idx)
         | 
| 97 | 
            +
                  self.column_count = [self.column_count || 0, idx.succ].max
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def build_row!(idx)
         | 
| 101 | 
            +
                  self.row_count = [self.row_count || 0 , idx.succ].max
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
             | 
| 106 | 
            +
            end
         | 
| 107 | 
            +
            require_relative 'matrix_table'
         | 
    
        data/lib/rmatrix/version.rb
    CHANGED
    
    
    
        data/rmatrix.todo
    CHANGED
    
    | @@ -1,6 +1,10 @@ | |
| 1 | 
            +
             ☐ Refactor + tidy
         | 
| 2 | 
            +
             Tests:
         | 
| 3 | 
            +
              ☐ Indexing
         | 
| 4 | 
            +
              ☐ Assignment
         | 
| 5 | 
            +
             ✔ Add matrix assignment @done (17-02-28 08:32)
         | 
| 1 6 | 
             
             ✘ Use Numo::NArray (Not ready yet) @cancelled (16-09-29 08:23)
         | 
| 2 | 
            -
              | 
| 3 | 
            -
             ☐ Add random int matrix
         | 
| 7 | 
            +
             ✘ Add random int matrix @cancelled (17-02-27 09:19)
         | 
| 4 8 | 
             
             ✔ Implement to_tex for notebooks @done (16-09-29 08:23)
         | 
| 5 9 | 
             
             ✔ Update print @done (16-04-06 07:40)
         | 
| 6 10 | 
             
             ✔ Basic matrix functions and tests @done (16-04-06 07:40)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rmatrix
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.10
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Wouter Coppieters
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2017-08-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -158,6 +158,8 @@ files: | |
| 158 158 | 
             
            - lib/rmatrix/core.rb
         | 
| 159 159 | 
             
            - lib/rmatrix/indices.rb
         | 
| 160 160 | 
             
            - lib/rmatrix/matrix.rb
         | 
| 161 | 
            +
            - lib/rmatrix/matrix_table.rb
         | 
| 162 | 
            +
            - lib/rmatrix/print_table.rb
         | 
| 161 163 | 
             
            - lib/rmatrix/shortcuts.rb
         | 
| 162 164 | 
             
            - lib/rmatrix/typecode.rb
         | 
| 163 165 | 
             
            - lib/rmatrix/vector.rb
         |