diff options
Diffstat (limited to 'Data/Libraries/Penlight/spec/array2d_spec.lua')
-rw-r--r-- | Data/Libraries/Penlight/spec/array2d_spec.lua | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/Data/Libraries/Penlight/spec/array2d_spec.lua b/Data/Libraries/Penlight/spec/array2d_spec.lua new file mode 100644 index 0000000..3fd0085 --- /dev/null +++ b/Data/Libraries/Penlight/spec/array2d_spec.lua @@ -0,0 +1,557 @@ +local array2d = require("pl.array2d") + +describe("pl.array2d", function() + + describe("new()", function() + it("creates an empty 2d array", function() + assert.same({{},{},{}}, array2d.new(3,3,nil)) + end) + + it("creates a value-filled 2d array", function() + assert.same({{99,99,99}, + {99,99,99}, + {99,99,99}}, array2d.new(3,3,99)) + end) + + it("creates a function-filled 2d array", function() + assert.same({{2,3,4}, + {3,4,5}, + {4,5,6}}, array2d.new(3,3,function(i,j) return i+j end)) + end) + end) + + describe("size()", function() + it("returns array size", function() + local a = array2d.new(3,5,99) + assert.same({3,5}, {array2d.size(a)}) + end) + + it("returns 0 columns for nil arrays", function() + local a = array2d.new(3,5,nil) + assert.same({3,0}, {array2d.size(a)}) + end) + end) + + describe("column()", function() + it("returns a column copy", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same({1,3,5}, array2d.column(a,1)) + assert.same({2,4,6}, array2d.column(a,2)) + end) + end) + + describe("row()", function() + it("returns a row copy", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same({1,2}, array2d.row(a,1)) + -- next test: need to remove the metatable to prevent comparison by + -- metamethods in Lua 5.3 and 5.4 + assert.not_equal(a[1], setmetatable(array2d.row(a,1),nil)) + assert.same({3,4}, array2d.row(a,2)) + assert.same({5,6}, array2d.row(a,3)) + end) + end) + + describe("map()", function() + it("maps a function on an array", function() + local a1 = array2d.new(2,3,function(i,j) return i+j end) + local a2 = array2d.map(function(a,b) return a .. b end, a1, "x") + assert.same({{"2x","3x","4x"}, + {"3x","4x","5x"}}, a2) + end) + end) + + describe("reduce_rows()", function() + it("reduces rows", function() + local a = {{ 1, 2, 3, 4}, + { 10, 20, 30, 40}, + { 100, 200, 300, 400}, + {1000,2000,3000,4000}} + assert.same({10,100,1000,10000},array2d.reduce_rows('+',a)) + end) + end) + + describe("reduce_cols()", function() + it("reduces columns", function() + local a = {{ 1, 2, 3, 4}, + { 10, 20, 30, 40}, + { 100, 200, 300, 400}, + {1000,2000,3000,4000}} + assert.same({1111,2222,3333,4444},array2d.reduce_cols('+',a)) + end) + end) + + describe("reduce2()", function() + it("recuces array to scalar", function() + local a = {{1,10}, + {2,10}, + {3,10}} + assert.same(60, array2d.reduce2('+','*',a)) + end) + end) + + describe("map2()", function() + it("maps over 2 arrays", function() + local b = {{10,20}, + {30,40}} + local a = {{1,2}, + {3,4}} + -- 2 2d arrays + assert.same({{11,22},{33,44}}, array2d.map2('+',2,2,a,b)) + -- 1d, 2d + assert.same({{11,102},{13,104}}, array2d.map2('+',1,2,{10,100},a)) + -- 2d, 1d + assert.same({{1,-2},{3,-4}},array2d.map2('*',2,1,a,{1,-1})) + end) + end) + + describe("product()", function() + it("creates a product array", function() + local a = array2d.product('..',{1,2,3},{'a','b','c'}) + assert.same({{'1a','2a','3a'},{'1b','2b','3b'},{'1c','2c','3c'}}, a) + + local a = array2d.product('{}',{1,2},{'a','b','c'}) + assert.same({{{1,'a'},{2,'a'}},{{1,'b'},{2,'b'}},{{1,'c'},{2,'c'}}}, a) + end) + end) + + describe("flatten()", function() + it("flattens a 2darray", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same( {1,2,3,4,5,6}, array2d.flatten(a)) + end) + + it("keeps a nil-array 'square'", function() + local a = {{ 1,2}, + {nil,4}, + {nil,6}} + assert.same( {1,2,nil,4,nil,6}, array2d.flatten(a)) + end) + end) + + describe("reshape()", function() + it("reshapes array in new nr of rows", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.reshape(a, 2, false) + assert.same({{ 1, 2, 3, 4, 5, 6}, + { 7, 8, 9,10,11,12}}, b) + local c = array2d.reshape(b, 4, false) + assert.same(a, c) + end) + it("reshapes array in new nr of rows, column order", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}} + local b = array2d.reshape(a, 3, true) + assert.same({{ 1, 4, 7}, + { 2, 5, 8}, + { 3, 6, 9}}, b) + end) + end) + + describe("transpose()", function() + it("transposes a 2d array", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}} + local b = array2d.transpose(a) + assert.same({{ 1, 4, 7}, + { 2, 5, 8}, + { 3, 6, 9}}, b) + + local a = {{ 1, 2, 3, 4, 5}, + { 6, 7, 8, 9, 10}} + local b = array2d.transpose(a) + assert.same({{ 1, 6}, + { 2, 7}, + { 3, 8}, + { 4, 9}, + { 5,10}}, b) + end) + end) + + describe("swap_rows()", function() + it("swaps 2 rows, in-place", function() + local a = {{1,2}, + {3,4}, + {5,6}} + local b = array2d.swap_rows(a, 1, 3) + assert.same({{5,6}, + {3,4}, + {1,2}}, b) + assert.equal(a, b) + end) + end) + + describe("swap_cols()", function() + it("swaps 2 columns, in-place", function() + local a = {{1,2,3}, + {4,5,6}, + {7,8,9}} + local b = array2d.swap_cols(a, 1, 3) + assert.same({{3,2,1}, + {6,5,4}, + {9,8,7}}, b) + assert.equal(a, b) + end) + end) + + describe("extract_rows()", function() + it("extracts rows", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.extract_rows(a, {1, 3}) + assert.same({{1,2,3}, + {7,8,9}}, b) + end) + end) + + describe("extract_cols()", function() + it("extracts colums", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.extract_cols(a, {1, 2}) + assert.same({{ 1, 2}, + { 4, 5}, + { 7, 8}, + {10,11}}, b) + end) + end) + + describe("remove_row()", function() + it("removes a row", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + array2d.remove_row(a, 2) + assert.same({{ 1, 2, 3}, + { 7, 8, 9}, + {10,11,12}}, a) + end) + end) + + describe("remove_col()", function() + it("removes a colum", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + array2d.remove_col(a, 2) + assert.same({{ 1, 3}, + { 4, 6}, + { 7, 9}, + {10,12}}, a) + end) + end) + + describe("parse_range()", function() + it("parses A1:B2 format", function() + assert.same({4,11,7,12},{array2d.parse_range("K4:L7")}) + assert.same({4,28,7,54},{array2d.parse_range("AB4:BB7")}) + -- test Col R since it might be mixed up with RxCx format + assert.same({4,18,7,18},{array2d.parse_range("R4:R7")}) + end) + + it("parses A1 format", function() + assert.same({4,11},{array2d.parse_range("K4")}) + -- test Col R since it might be mixed up with RxCx format + assert.same({4,18},{array2d.parse_range("R4")}) + end) + + it("parses R1C1:R2C2 format", function() + assert.same({4,11,7,12},{array2d.parse_range("R4C11:R7C12")}) + end) + + it("parses R1C1 format", function() + assert.same({4,11},{array2d.parse_range("R4C11")}) + end) + end) + + describe("range()", function() + it("returns a range", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.range(a, "B3:C4") + assert.same({{ 8, 9}, + {11,12}}, b) + end) + end) + + describe("default_range()", function() + it("returns the default range", function() + local a = array2d.new(4,6,1) + assert.same({1,1,4,6}, {array2d.default_range(a, nil, nil, nil, nil)}) + end) + + it("accepts negative indices", function() + local a = array2d.new(4,6,1) + assert.same({2,2,3,5}, {array2d.default_range(a, -3, -5, -2, -2)}) + end) + + it("corrects out of bounds indices", function() + local a = array2d.new(4,6,1) + assert.same({1,1,4,6}, {array2d.default_range(a, -100, -100, 100, 100)}) + end) + end) + + describe("slice()", function() + it("returns a slice", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,3,2,4,3) + assert.same({{ 8, 9}, + {11,12}}, b) + end) + + it("returns a single row if rows are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,4,1,4,3) + assert.same({10,11,12}, b) + end) + + it("returns a single column if columns are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,1,3,4,3) + assert.same({3,6,9,12}, b) + end) + + it("returns a single value if rows and columns are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,2,2,2,2) + assert.same(5, b) + end) + end) + + describe("set()", function() + it("sets a range to a value", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + array2d.set(a,0,2,2,3,3) + assert.same({{1 ,2 ,3}, + {4 ,0 ,0}, + {7 ,0 ,0}, + {10,11,12}}, a) + end) + + it("sets a range to a function value", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local x = 10 + local args = {} + local f = function(r,c) + args[#args+1] = {r,c} + x = x + 1 + return x + end + array2d.set(a,f,3,1,4,3) + assert.same({{1 ,2 ,3}, + {4 ,5 ,6}, + {11,12,13}, + {14,15,16}}, a) + -- validate args used to call the function + assert.same({{3,1},{3,2},{3,3},{4,1},{4,2},{4,3}}, args) + end) + end) + + describe("write()", function() + it("writes array to a file", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local f = setmetatable({}, { + __index = { + write = function(self,str) + self[#self+1] = str + end + } + }) + array2d.write(a,f,"(%s)") + f = table.concat(f) + assert.equal([[(1)(2)(3) +(4)(5)(6) +(7)(8)(9) +(10)(11)(12) +]],f) + end) + + it("writes partial array to a file", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local f = setmetatable({}, { + __index = { + write = function(self,str) + self[#self+1] = str + end + } + }) + array2d.write(a,f,"(%s)", 1,1,2,2) + f = table.concat(f) + assert.equal([[(1)(2) +(4)(5) +]],f) + end) + end) + + describe("forall()", function() + it("runs all value and row functions", function() + local r = {} + local t = 0 + local fval = function(row, j) t = t + row[j] end + local frow = function(i) r[#r+1] = t; t = 0 end + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + array2d.forall(a, fval, frow) + assert.same({6, 15, 24, 33}, r) + r = {} + array2d.forall(a, fval, frow, 2,2,4,3) + assert.same({11, 17, 23}, r) + end) + + end) + + describe("move()", function() + it("moves block to destination aray", function() + local a = array2d.new(4,4,0) + local b = array2d.new(3,3,1) + array2d.move(a,2,2,b) + assert.same({{0,0,0,0}, + {0,1,1,1}, + {0,1,1,1}, + {0,1,1,1}}, a) + end) + end) + + describe("iter()", function() + it("iterates all values", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for v, i, j in array2d.iter(a) do + r[#r+1] = v + assert.is_nil(i) + assert.is_nil(j) + end + assert.same({1,2,3,4,5,6,7,8,9,10,11,12}, r) + end) + + it("iterates all values and indices", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + local ri = {} + local rj = {} + for i, j, v in array2d.iter(a,true) do + r[#r+1] = v + ri[#ri+1] = i + rj[#rj+1] = j + end + assert.same({1,2,3,4,5,6,7,8,9,10,11,12}, r) + assert.same({1,1,1,2,2,2,3,3,3,4,4,4}, ri) + assert.same({1,2,3,1,2,3,1,2,3,1,2,3}, rj) + end) + + it("iterates all values of a 2d array part", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for v, i, j in array2d.iter(a,false,2,2,4,3) do + r[#r+1] = v + assert.is_nil(i) + assert.is_nil(j) + end + assert.same({5,6,8,9,11,12}, r) + end) + + it("iterates all values and indices of a 2d array part", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + local ri = {} + local rj = {} + for i, j, v in array2d.iter(a,true,2,2,4,3) do + r[#r+1] = v + ri[#ri+1] = i + rj[#rj+1] = j + end + assert.same({5,6,8,9,11,12}, r) + assert.same({2,2,3,3,4,4}, ri) + assert.same({2,3,2,3,2,3}, rj) + end) + end) + + describe("columns()", function() + it("iterates all columns", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for col, idx in array2d.columns(a) do + r[#r+1] = col + col.idx = idx + end + assert.same({{1,4,7,10, idx=1},{2,5,8,11, idx=2},{3,6,9,12, idx=3}}, r) + end) + end) + + describe("rows()", function() + it("iterates all columns", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for row, idx in array2d.rows(a) do + r[#r+1] = row + row.idx = idx + end + assert.same({{1,2,3, idx=1},{4,5,6, idx=2}, + {7,8,9, idx=3},{10,11,12, idx=4}}, r) + end) + end) + +end) |