Module: RMatrix::Indices

Included in:
Matrix
Defined in:
lib/rmatrix/indices.rb

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



38
39
40
41
42
43
44
45
46
# File 'lib/rmatrix/indices.rb', line 38

def method_missing(name, *args, &block)
  if row_map && row_map.include?(name)
    self[name, true]
  elsif column_map && column_map.include?(name)
    self[true, name]
  else
    super
  end
end

Instance Method Details

#[](*args) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/rmatrix/indices.rb', line 9

def [](*args)
  indices           = unmap_args(args)
  result_row_map    = build_result_map(self.row_map, indices.first, self.rows)      if self.row_map
  result_column_map = build_result_map(self.column_map, indices.last, self.columns) if self.column_map

  row_indices, column_indices = indices

  result_column_label_map = nil
  result_row_label_map = nil

  if row_label_map
    case row_indices
    when true then result_row_label_map = row_label_map
    else
      result_row_label_map = walk_indices(row_indices, row_label_map).each_slice(2).to_h
    end
  end

  if column_label_map
    case column_indices
    when true then result_column_label_map = column_label_map
    else
      result_column_label_map = walk_indices(column_indices, column_label_map).each_slice(2).to_h
    end
  end

  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]
end

#[]=(*args, value) ⇒ Object



4
5
6
7
# File 'lib/rmatrix/indices.rb', line 4

def []=(*args, value)
  indices = unmap_args(args)
  raw[*indices] = value
end

#build_result_map(existing, indices, size) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rmatrix/indices.rb', line 77

def build_result_map(existing, indices, size)
  return existing if indices == true
  result_map = {}
  indexify(indices, result_map, size)
  result_map.default_proc =  ->(h,k) do
    existing_index = existing[k]
    case existing_index
    when TrueClass
      existing_index
    when Range
      if existing_index.exclude_end?
        h[k] = h[existing_index.first]...h[existing_index.end]
      else
        h[k] = h[existing_index.first]..h[existing_index.end]
      end
    when nil
      raise "Couldn't find key #{k} in index mapping"
    else
      h[existing_index]
    end
  end
  result_map
end

#indexify(indices, results, size, total = 0) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rmatrix/indices.rb', line 101

def indexify(indices, results, size, total=0)
  Array(indices).each do |index|
    case index
    when TrueClass
      (0...size).each do |i|
        results[i] = i
      end
    when 1.class
      results[index] ||= total
      total += 1
    when Array
      indexify(index, results, size, total)
    when Range
      inclusive  = index.exclude_end? ? index.first..(index.end - 1) : index
      flat_range = inclusive.end < inclusive.first ? [*inclusive.end..inclusive.first].reverse : [*inclusive]
      flat_range.each do |elm|
        indexify(elm, results, size, total)
      end
    end
  end
end

#rawObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rmatrix/indices.rb', line 59

def raw
  @raw ||= begin
    raw = Struct.new(:narray, :typecode).new(self.narray, self.typecode)
    def raw.[](*args, column_map: nil, row_map: nil, row_label_map: nil, column_label_map: nil)
      begin
        args.all?{|x| 1.class === 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)
      rescue StandardError => e
        raise IndexError.new("Error #{e.message} - accessing index at #{args}. Shape is #{narray.shape.reverse}")
      end
    end

    def raw.[]=(*args, value)
      narray[*args.reverse] = value
    end
    raw
  end
end

#unmap_args(args) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/rmatrix/indices.rb', line 123

def unmap_args(args)
  if args.length == 1
    if row_map
      return [Array(unmap_index(self.row_map, args[0])), true] rescue nil
    end
    if column_map
      return [true, Array(unmap_index(self.column_map, args[0]))] rescue nil
    end
    return [args[0]]
  else
    row_index    = self.row_map ? unmap_index(self.row_map, args[0]) : args[0]
    column_index = self.column_map ? unmap_index(self.column_map, args[1]) : args[1]
    column_index = [column_index] if column_index.kind_of?(1.class)
    [
      row_index,
      column_index
    ]
  end
end

#unmap_index(map, columns) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/rmatrix/indices.rb', line 143

def unmap_index(map, columns)
  case columns
  when TrueClass, FalseClass
    columns
  when Array
    columns.map{|col| unmap_index(map, col)}.flatten
  when Range
    first = unmap_index(map, columns.first)
    last = unmap_index(map, columns.end)
    first = Range === first ? first.first : first
    if columns.exclude_end?
      last = Range === last ? last.first : last
      first...last
    else
      last = Range === last ? last.end : last
      first..last
    end
  else
    index = (map[columns] rescue nil)
    index = columns if !index && columns.kind_of?(1.class)
    raise "Value not present in index mapping: #{columns}" unless index
    index
  end
end

#walk_indices(indices, parent, i = {index: 0}) ⇒ Object



48
49
50
51
52
53
54
55
56
57
# File 'lib/rmatrix/indices.rb', line 48

def walk_indices(indices, parent, i={index: 0})
  Array(indices).flat_map do |index|
    res = case index
    when Array, Range then walk_indices(index.to_a, parent, i)
    else [i[:index], parent[index]]
    end
    i[:index] += 1
    res
  end
end