multimatrix 0.2
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 +7 -0
- data/lib/multimatrix.rb +296 -0
- data/test/test_multimatrix.rb +142 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 270b3c84f142d440457ef16d2f3632351234d405
|
4
|
+
data.tar.gz: 58401fba050650b4aa3e076fd050c7de8a8159a2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aa9c8a1215fd93ce7d6bf575f674f42bde33c06a7554ef7c73de7fef07c8a940604eec01a7485790d8044d60be790922844aa627b467cd4cd14002b9de43e454
|
7
|
+
data.tar.gz: ca4e08406a23535a8856fb48852cba777b6371da47dbcdb123d570f1a887f2c241416e6a674524a4389b0d98fb99db09b3a8c5f4e1e49e12ebe16ff2b1b05b01
|
data/lib/multimatrix.rb
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
class MultiMatrixException < Exception
|
2
|
+
end
|
3
|
+
|
4
|
+
# An n-dimensonal matrix, where dimensions are labels
|
5
|
+
#
|
6
|
+
# Imagine: your urgent need is to store a dataset more than 1 or 2 dimensions large.
|
7
|
+
# The default way to do this is tu use multi dimensional arrays, like "array[][][]" for
|
8
|
+
# example. Inserting or retrieveing a value from this dataset would be kind of an easy task,
|
9
|
+
# but what happens when You have to summarize all the elements of a dimension. For example
|
10
|
+
# sum all the elements where the second level array's index is 2. You have to loop through
|
11
|
+
# n*n*n elements, just to find some of them. Tedious.
|
12
|
+
#
|
13
|
+
# MultiMatrix comes to the rescue.
|
14
|
+
#
|
15
|
+
# MultiMatrix makes it easy to create multi-level data structures, and makes finding and looping through
|
16
|
+
# them nice and easy. And fast.
|
17
|
+
#
|
18
|
+
# @author Gergely Dömsödi <mailto:gergely.domsodi@uhusystems.com>
|
19
|
+
#
|
20
|
+
# To easily show an example, and concept of this class let's see a 2 dimensional array
|
21
|
+
#
|
22
|
+
# m = MultiMatrix.new(:x, :y)
|
23
|
+
# m.insert(:x => 1, :y = 3) = 10
|
24
|
+
# m.insert(:x => 2, :y = 1) = 20
|
25
|
+
# m.insert(:x => 2, :y =>2) = 30
|
26
|
+
#
|
27
|
+
# could be imagined as
|
28
|
+
# x| 1 | 2 | 3 |
|
29
|
+
# y |___|___|___|
|
30
|
+
# 1 | ? | 20| ? |
|
31
|
+
# |___|___|___|
|
32
|
+
# 2 | ? | 30| ? |
|
33
|
+
# |___|___|___|
|
34
|
+
# 3 | 10| ? | ? |
|
35
|
+
# |___|___|___|
|
36
|
+
#
|
37
|
+
# >> m.sum(x: 2)
|
38
|
+
# => 50
|
39
|
+
# >> m.sum(x: 3)
|
40
|
+
# => 0
|
41
|
+
# >> m.to_a(y: 2)
|
42
|
+
# => [30]
|
43
|
+
# >> m[:x => 1, :y => 1]
|
44
|
+
# => nil
|
45
|
+
# >> m[:x => 3] == MultiMatrix.new(:y)
|
46
|
+
# => true
|
47
|
+
#
|
48
|
+
# Usage:
|
49
|
+
#
|
50
|
+
# >> x = MultiMatrix.new(:x, :y, :z)
|
51
|
+
# >> x[:x => 1, :y => 1, :z => 1] = 1
|
52
|
+
# >> x[:x => 1, :y => 1, :z => 2] = 1
|
53
|
+
# >> x[:x => 2, :y => 1, :z => 2] = 1
|
54
|
+
#
|
55
|
+
# >> x[:x => 1, :y => 1, :z => 1]
|
56
|
+
# => 1
|
57
|
+
#
|
58
|
+
# >> x[:x => 1, :y => 1]
|
59
|
+
# => MultiMatrix({:z=>2}=>2)
|
60
|
+
#
|
61
|
+
# >> x.sum(:x => 1)
|
62
|
+
# => 2
|
63
|
+
# >> x.sum(:z => 1)
|
64
|
+
# => 1
|
65
|
+
# >> x.to_a(:z => 1)
|
66
|
+
# => [1]
|
67
|
+
#
|
68
|
+
# Wait! There is more:
|
69
|
+
#
|
70
|
+
# >> x[:z => [1,2]]
|
71
|
+
# => [1,1,1]
|
72
|
+
# >> x.sum(:z => [1,2])
|
73
|
+
# => 3
|
74
|
+
|
75
|
+
class MultiMatrix
|
76
|
+
|
77
|
+
# Creates a new MultiMatrix object, where labels will be the dimensions of the dataset
|
78
|
+
# use labels appropriate for Hash keys, because they will be stored as such internally.
|
79
|
+
# labels could be Symbols, Integers, even ActiveModel objects, the only requirement for it that it have to
|
80
|
+
# have a meaningful == method.
|
81
|
+
# @param labels an [Array] of values to be used as dimension labels
|
82
|
+
def initialize(*labelskeys)
|
83
|
+
raise MultiMatrixException, "no dimensions" if labelskeys.length == 0
|
84
|
+
@labels = labelskeys
|
85
|
+
@dim = @labels.length
|
86
|
+
@values = Hash.new
|
87
|
+
@values_by_id = Hash.new
|
88
|
+
@labels_by_id = Hash.new
|
89
|
+
@sumcache = {}
|
90
|
+
@seq = 0
|
91
|
+
@finderhash = {}
|
92
|
+
end
|
93
|
+
|
94
|
+
# Inserts a value to the data set.
|
95
|
+
#
|
96
|
+
# @param labels [Hash] the position where to insert the value.
|
97
|
+
# beware, at insert all dimension of the positin must be given
|
98
|
+
# @param value The value to be inserted
|
99
|
+
# @return [true] on success, raises MultiMatrixException otherwise
|
100
|
+
def insert(labels, value)
|
101
|
+
if check_labels(labels) and labels.keys.length == @dim
|
102
|
+
if @values.key?(labels)
|
103
|
+
id = @values[labels]
|
104
|
+
if block_given?
|
105
|
+
save_value(labels, yield(get_value(labels), value), :override => id)
|
106
|
+
else
|
107
|
+
save_value(labels, get_value(labels) + value, :override => id)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
save_value(labels, value)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
raise MultiMatrixException, 'not enough key supplied'
|
114
|
+
end
|
115
|
+
@sumcache = {}
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Executes block on all value at position given by labels
|
120
|
+
# @param labels finder hash
|
121
|
+
def each(labels = {})
|
122
|
+
if check_labels(labels) and labels.keys.length <= @dim
|
123
|
+
ids = find_ids(labels)
|
124
|
+
ids.each do |id|
|
125
|
+
if block_given?
|
126
|
+
yield @values_by_id[id]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Same as Enumerable#inject, but filter hash is accepted
|
133
|
+
# @param labels finder hash
|
134
|
+
# @param default beginning value of the memo
|
135
|
+
def inject(labels = {}, default = 0)
|
136
|
+
memo = default
|
137
|
+
if check_labels(labels) and labels.keys.length <= @dim
|
138
|
+
ids = find_ids(labels)
|
139
|
+
ids.each do |id|
|
140
|
+
if block_given?
|
141
|
+
memo = yield memo, @values_by_id[id]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
return memo
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns an array of values matching @param labels
|
149
|
+
# @param labels finder hash
|
150
|
+
# @return [Array] values found
|
151
|
+
def to_a(labels = {})
|
152
|
+
if check_labels(labels)
|
153
|
+
ids=find_ids(labels)
|
154
|
+
return ids.map{|id| @values_by_id[id]}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Summarizes all elements matching labels
|
159
|
+
# a little faster than using MultiMatrix#inject(labels) {|a,b| a+b} because of two factors:
|
160
|
+
# - if every dimension is given, sum return only one element without looping through the data structure
|
161
|
+
# - sum is cached so if sum is called twice with the same selector hash, the result is given back instantly
|
162
|
+
# @param labels finder hash
|
163
|
+
# @param default default value of sum
|
164
|
+
def sum(labels = {}, default = 0)
|
165
|
+
if check_labels(labels)
|
166
|
+
if labels.keys.length == @dim and labels.values.find_all {|val| val.class.to_s == 'Array'}.empty?
|
167
|
+
return get_value(labels)
|
168
|
+
end
|
169
|
+
if @sumcache.key?(labels)
|
170
|
+
return @sumcache[labels]
|
171
|
+
end
|
172
|
+
ret = self.inject(labels, default) {|a,b| a+b}
|
173
|
+
@sumcache[labels] = ret
|
174
|
+
ret
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Retrieves a value
|
179
|
+
# If every dimension is given, retrieve just a value at the specified position,
|
180
|
+
# if not, retrieves an MultiMatrix of the matching elements, leaving the fixed dimensions behind
|
181
|
+
# @param labels finder hash
|
182
|
+
# @return value/MultiMatrix
|
183
|
+
def retrieve(labels = {})
|
184
|
+
if check_labels(labels)
|
185
|
+
if labels.keys.length < @dim or labels.values.find_all {|val| val.class == Array}.length > 0
|
186
|
+
tmp = MultiMatrix.new(*(@labels - labels.keys.find_all {|val| labels[val].class != Array}))
|
187
|
+
ids = find_ids(labels)
|
188
|
+
ids.each do |id|
|
189
|
+
hash = @labels_by_id[id]
|
190
|
+
labels.keys.find_all {|val| labels[val].class != Array}.each do |key|
|
191
|
+
hash.delete(key)
|
192
|
+
end
|
193
|
+
tmp[hash] = @values_by_id[id]
|
194
|
+
end
|
195
|
+
return tmp
|
196
|
+
elsif labels.keys.length == @dim
|
197
|
+
return get_value(labels)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# return the possible values of a dimension
|
203
|
+
# where values match the labels given in [rest]
|
204
|
+
# @param needle a key of the labels hash
|
205
|
+
# @param rest a selector hash
|
206
|
+
def values_for_label(needle, rest = {})
|
207
|
+
raise MultiMatrixException, 'labels don\'t match: '+rest.keys.join(",") unless check_labels(rest)
|
208
|
+
raise MultiMatrixException, 'label does not exist' unless check_labels({needle => nil})
|
209
|
+
ids = find_ids(rest)
|
210
|
+
ids.map{|id| @labels_by_id[id][needle]}
|
211
|
+
end
|
212
|
+
|
213
|
+
alias_method :[], :retrieve
|
214
|
+
alias_method :[]=, :insert
|
215
|
+
|
216
|
+
# Test the equality of two NMatrices
|
217
|
+
|
218
|
+
# NMatrices are equal if they have the same labels,
|
219
|
+
# label values, and all their respective values are equal
|
220
|
+
# @param other [MultiMatrix]
|
221
|
+
def ==(other)
|
222
|
+
[[self, other],[other,self]].each do |x|
|
223
|
+
x.first.keys do |k|
|
224
|
+
if !x.last.key?(k)
|
225
|
+
return false
|
226
|
+
end
|
227
|
+
if x.last[k] != x.first[k]
|
228
|
+
return false
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
return true
|
233
|
+
end
|
234
|
+
|
235
|
+
# @return labels in MultiMatrix
|
236
|
+
def keys
|
237
|
+
@values.keys
|
238
|
+
end
|
239
|
+
|
240
|
+
# @return String representation of an MultiMatrix - shown as a Hash of label => value pairs
|
241
|
+
def to_s
|
242
|
+
hash = {}
|
243
|
+
@values.each_pair do |k,v|
|
244
|
+
hash[k] = @values_by_id[v]
|
245
|
+
end
|
246
|
+
hash.to_s
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
def check_labels(to_check)
|
252
|
+
raise MultiMatrixException, 'labels not a hash' if to_check.class != Hash
|
253
|
+
raise MultiMatrixException, 'labels hash contains an unknown label' unless (to_check.keys-@labels).empty?
|
254
|
+
return true;
|
255
|
+
end
|
256
|
+
|
257
|
+
def get_value(labels)
|
258
|
+
@values_by_id[@values[labels]]
|
259
|
+
end
|
260
|
+
|
261
|
+
def save_value(labels, val, options = {})
|
262
|
+
if options.key?(:override)
|
263
|
+
@values_by_id[options[:override]] = val
|
264
|
+
else
|
265
|
+
id = generate_id
|
266
|
+
@values[labels] = id
|
267
|
+
@values_by_id[id] = val
|
268
|
+
@labels_by_id[id] = labels
|
269
|
+
labels.each_pair do |k, v|
|
270
|
+
@finderhash[k] ||= {}
|
271
|
+
@finderhash[k][v] ||= []
|
272
|
+
@finderhash[k][v].push(id)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def find_ids(labels)
|
278
|
+
ids = @values.values
|
279
|
+
labels.each_pair do |k,v|
|
280
|
+
if v.class == Array
|
281
|
+
ids &= v.map {|v| @finderhash[k][v]}.flatten.uniq
|
282
|
+
elsif @finderhash[k][v].nil?
|
283
|
+
return []
|
284
|
+
else
|
285
|
+
ids &= @finderhash[k][v]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
return ids
|
289
|
+
end
|
290
|
+
|
291
|
+
def generate_id
|
292
|
+
@seq = @seq.succ
|
293
|
+
return @seq
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'multimatrix'
|
3
|
+
|
4
|
+
class MultiMatrixTest < Test::Unit::TestCase
|
5
|
+
def test_new
|
6
|
+
assert_raise(MultiMatrixException, "no dimensions") do
|
7
|
+
MultiMatrix.new()
|
8
|
+
end
|
9
|
+
assert_nothing_raised do
|
10
|
+
MultiMatrix.new(:x, :y, :z)
|
11
|
+
end
|
12
|
+
assert_equal MultiMatrix.new(:x,:y,:z).class, MultiMatrix
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_insert
|
16
|
+
x = MultiMatrix.new(:x, :y, :z)
|
17
|
+
|
18
|
+
assert_raise MultiMatrixException do
|
19
|
+
x[:x => 1 , :y => 1, :a => 1] = 1
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_raise MultiMatrixException do
|
23
|
+
x[:x => 1, :y => 1] = 1
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_raise ArgumentError do
|
27
|
+
x[] = 1
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_nothing_raised do
|
31
|
+
x[:x => 1, :y => 1, :z => 1] = 1
|
32
|
+
x[:x => 1, :y => 1, :z => 2] = 1
|
33
|
+
x[:x => 1, :y => 1, :z => 3] = 1
|
34
|
+
|
35
|
+
x[:x => 1, :y => 1, :z => 1] = 1
|
36
|
+
x.insert({:x => 1, :y => 1, :z => 1}, 1) {|a,b| a+b}
|
37
|
+
x.insert({:x => 1, :y => 1, :z => 1}, 1) {|a,b| a-b}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_values
|
42
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
43
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
44
|
+
|
45
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1], 1
|
46
|
+
|
47
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
48
|
+
|
49
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1], 2
|
50
|
+
|
51
|
+
x.insert({:i => 1, :j => 1, :x => 1, :y => 1, :z => 1}, 1) {|a,b| a-b}
|
52
|
+
|
53
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1], 1
|
54
|
+
|
55
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 1
|
56
|
+
|
57
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1], 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_equality
|
61
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
62
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
63
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 1
|
64
|
+
|
65
|
+
y = MultiMatrix.new(:i, :j, :x, :y, :z)
|
66
|
+
y[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
67
|
+
y[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 1
|
68
|
+
|
69
|
+
assert_equal x,y
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_MultiMatrix_returns
|
73
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
74
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
75
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 1
|
76
|
+
|
77
|
+
y = MultiMatrix.new(:z)
|
78
|
+
y[:z => 1] = 1
|
79
|
+
y[:z => 2] = 1
|
80
|
+
|
81
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1], y
|
82
|
+
assert_equal x[:i => 1, :j => 1, :x => 1, :y => 1, :z => [1,2]], y
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_sum
|
86
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
87
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
88
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 1
|
89
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 3] = 1
|
90
|
+
|
91
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 1] = 1
|
92
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 2] = 1
|
93
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 3] = 1
|
94
|
+
|
95
|
+
assert_equal x.sum({:y => 1}), 3
|
96
|
+
assert_equal x.sum({:z => 1}), 2
|
97
|
+
assert_equal x.sum({:z => 1, :y=> 1}), 1
|
98
|
+
assert_equal x.sum({:i => 1}), 6
|
99
|
+
assert_equal x.sum({:y => [1,2]}), 6
|
100
|
+
assert_equal x.sum({:y => [1,2], :z => [1,2]}), 4
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_to_a
|
105
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
106
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 1
|
107
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 2
|
108
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 3] = 3
|
109
|
+
|
110
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 1] = 4
|
111
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 2] = 5
|
112
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 3] = 6
|
113
|
+
|
114
|
+
assert_equal x.to_a.sort, [1,2,3,4,5,6]
|
115
|
+
assert_equal x.to_a(:i => 1).sort, [1,2,3,4,5,6]
|
116
|
+
assert_equal x.to_a(:z => 2).sort, [2,5]
|
117
|
+
assert_equal x.to_a(:y => 1).sort, [1,2,3]
|
118
|
+
assert_equal x.to_a(:y => 1, :z => 1), [1]
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_values_for_label
|
122
|
+
x = MultiMatrix.new(:i, :j, :x, :y, :z)
|
123
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 1] = 4
|
124
|
+
x[:i => 1, :j => 1, :x => 1, :y => 1, :z => 2] = 5
|
125
|
+
x[:i => 1, :j => 1, :x => 1, :y => 2, :z => 3] = 6
|
126
|
+
|
127
|
+
assert_equal x.values_for_label(:i), [1,1,1]
|
128
|
+
assert_equal x.values_for_label(:z).sort, [1,2,3]
|
129
|
+
assert_equal x.values_for_label(:y).sort, [1,1,2]
|
130
|
+
assert_equal x.values_for_label(:y, :z => 3).sort, [2]
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_nonexistent_values
|
134
|
+
x = MultiMatrix.new(:x, :y)
|
135
|
+
x[:x => 2, :y => 2] = 1
|
136
|
+
|
137
|
+
assert_nil x[:x => 1, :y => 1]
|
138
|
+
y = MultiMatrix.new(:y)
|
139
|
+
assert_equal x[:x => 1],y
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multimatrix
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.2'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gergely Dömsödi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: An n-dim matrix featuring labels
|
14
|
+
email: doome@uhusystems.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/multimatrix.rb
|
20
|
+
- test/test_multimatrix.rb
|
21
|
+
homepage: http://rubygems.org/gems/multimatrix
|
22
|
+
licenses:
|
23
|
+
- WTFPL
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubyforge_project:
|
41
|
+
rubygems_version: 2.1.11
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: n-dim Matrix!
|
45
|
+
test_files: []
|
46
|
+
has_rdoc:
|