view src/may/matrix/test/test_matrix.yeti @ 600:956074cc1f7c tip

Fix some tests, update subrepo
author Chris Cannam
date Fri, 15 May 2020 11:36:02 +0100
parents eb27901664cd
children
line wrap: on
line source

module may.matrix.test.test_matrix;

mat = load may.matrix;
vec = load may.vector;

import yeti.lang: FailureException;

{ compare, compareUsing } = load may.test;

compareMatrices = compareUsing mat.equal;

makeTests name flipper =
   (constMatrix n s = flipper (mat.constMatrix n s);
    zeroMatrix s = flipper (mat.zeroMatrix s);
    randomMatrix s = flipper (mat.randomMatrix s);
    identityMatrix s = flipper (mat.identityMatrix s);
    generate f s = flipper (mat.generate f s);
    newMatrix s data = flipper (mat.newMatrix s data);
    fromRows d = flipper (mat.fromRows (map vec.fromList d));
    fromColumns d = flipper (mat.fromColumns (map vec.fromList d));
[

"constMatrixEmpty-\(name)": \(
    m = constMatrix 2 { rows = 0, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 0 }
),

"constMatrixEmpty2-\(name)": \(
    compare (mat.size (constMatrix 2 { rows = 0, columns = 4 })) { columns = 4, rows = 0 } and
        compare (mat.size (constMatrix 2 { rows = 4, columns = 0 })) { columns = 0, rows = 4 } and
        compare (vec.list (mat.getColumn 2 (constMatrix 2 { rows = 0, columns = 4 }))) [] and
        compare (map vec.list (mat.asRows (constMatrix 2 { rows = 4, columns = 0 }))) [[],[],[],[]] and
        compare (vec.list (mat.getRow 2 (constMatrix 2 { rows = 3, columns = 0 }))) []
),

"constMatrix-\(name)": \(
    m = constMatrix 2 { rows = 3, columns = 4 };
    compare (mat.size m) { columns = 4, rows = 3 } and
        all id (map do row: compare (vec.list (mat.getRow row m)) [2,2,2,2] done [0..2]) and
        all id (map do col: compare (vec.list (mat.getColumn col m)) [2,2,2] done [0..3])
),

"randomMatrixEmpty-\(name)": \(
    m = randomMatrix { rows = 0, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 0 }
),

"randomMatrix-\(name)": \(
    m = randomMatrix { rows = 3, columns = 4 };
    compare (mat.size m) { columns = 4, rows = 3 }
),

"zeroMatrixEmpty-\(name)": \(
    m = zeroMatrix { rows = 0, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 0 }
),

"zeroMatrix-\(name)": \(
    m = zeroMatrix { rows = 3, columns = 4 };
    compare (mat.size m) { columns = 4, rows = 3 } and
        all id (map do row: compare (vec.list (mat.getRow row m)) [0,0,0,0] done [0..2]) and
        all id (map do col: compare (vec.list (mat.getColumn col m)) [0,0,0] done [0..3])
),

"identityMatrixEmpty-\(name)": \(
    m = identityMatrix { rows = 0, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 0 }
),

"identityMatrix-\(name)": \(
    m = identityMatrix { rows = 3, columns = 4 };
    compare (mat.size m) { columns = 4, rows = 3 } and
        all id (map do row: compare (vec.list (mat.getRow row m)) [1,1,1,1] done [0..2]) and
        all id (map do col: compare (vec.list (mat.getColumn col m)) [1,1,1] done [0..3])
),

"generateEmpty-\(name)": \(
    m = generate do row col: 6 done { rows = 0, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 0 }
),

"generateEmpty2-\(name)": \(
    m = generate do row col: 6 done { rows = 4, columns = 0 };
    compare (mat.size m) { columns = 0, rows = 4 }
),

"generate-\(name)": \(
    m = generate do row col: row * 10 + col done { rows = 2, columns = 3 };
    compare (vec.list (mat.getRow 0 m)) [0,1,2] and
        compare (vec.list (mat.getRow 1 m)) [10,11,12]
),

"widthAndHeight-\(name)": \(
    m = constMatrix 2 { rows = 3, columns = 4 };
    compare (mat.size m) { columns = mat.width m, rows = mat.height m }
),

"newMatrix-rows-\(name)": \(
    rowc rr = Rows (map vec.fromList rr);
    m1 = newMatrix { rows = 0, columns = 0 } (rowc []);
    m2 = newMatrix { rows = 2, columns = 0 } (rowc [[],[]]);
    m3 = newMatrix { rows = 3, columns = 2 } (rowc [[1,2],[3,4],[5,6]]);
    compare (mat.size m1) { rows = 0, columns = 0 } and
        compare (mat.size m2) { rows = 2, columns = 0 } and
        compare (mat.size m3) { rows = 3, columns = 2 } and
        compareMatrices m3 (fromRows [[1,2],[3,4],[5,6]]);
),

"newMatrix-columns-\(name)": \(
    colc cc = Columns (map vec.fromList cc);
    m1 = newMatrix { rows = 0, columns = 0 } (colc []);
    m2 = newMatrix { rows = 0, columns = 2 } (colc [[],[]]);
    m3 = newMatrix { rows = 2, columns = 3 } (colc [[1,2],[3,4],[5,6]]);
    compare (mat.size m1) { rows = 0, columns = 0 } and
        compare (mat.size m2) { rows = 0, columns = 2 } and
        compare (mat.size m3) { rows = 2, columns = 3 } and
        compareMatrices m3 (fromColumns [[1,2],[3,4],[5,6]]);
),

"newMatrix-fail-\(name)": \(
    rowc rr = Rows (map vec.fromList rr);
    colc cc = Columns (map vec.fromList cc);
    all id
       (map do t:
            try
                \() (t ());
                false;
            catch FailureException e:
                true;
            yrt
        done
        [
        \(newMatrix { rows = 0, columns = 0 } (rowc [[]])),
        \(newMatrix { rows = 0, columns = 0 } (colc [[]])),
        \(newMatrix { rows = 2, columns = 0 } (rowc [[]])),
        \(newMatrix { rows = 0, columns = 2 } (colc [[]])),
        \(newMatrix { rows = 2, columns = 2 } (rowc [[],[]])),
        \(newMatrix { rows = 2, columns = 2 } (colc [[],[]])),
        \(newMatrix { rows = 2, columns = 3 } (rowc [[1,2],[3,4,5]])),
        \(newMatrix { rows = 3, columns = 2 } (colc [[1,2],[3,4,5]])),
        \(newMatrix { rows = 2, columns = 3 } (rowc [[1,2,3],[4,5]])),
        \(newMatrix { rows = 3, columns = 2 } (colc [[1,2,3],[4,5]])),
        \(newMatrix { rows = 2, columns = 3 } (rowc [[1,2,3],[4,5,6],[7,8,9]])),
        \(newMatrix { rows = 3, columns = 2 } (colc [[1,2,3],[4,5,6],[7,8,9]])),
        \(newMatrix { rows = 2, columns = 3 } (rowc [[1,2,3]])),
        \(newMatrix { rows = 3, columns = 2 } (colc [[1,2,3]]))
        ]);
),

"equal-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    n = m;
    p = fromRows [[1,0,3],[4,5,6]];
    q = fromColumns [[1,0,3],[4,5,6]];
    r = fromColumns [[1,4],[0,5]];
    compareMatrices m n and
        compareMatrices m p and
        compareMatrices n p and
        not mat.equal m q and
        not mat.equal m r
),

"equalUnder-\(name)": \(
    p = fromColumns [[1,2,3],[4,5,6]];
    q = fromColumns [[1,2,3],[4,5,6]];
    r = fromColumns [[4,3,1],[3,1,2]];
    s = fromColumns [[1,4,5],[6,7,8]];
    t = fromColumns [[1,4,5],[6,7,9]];
    mat.equalUnder (==) p p and
        mat.equalUnder (==) p q and
        mat.equalUnder (!=) p r and
        mat.equalUnder do a b: a % 2 == b % 2 done p s and
        not mat.equalUnder do a b: a % 2 == b % 2 done p t
),

"at-\(name)": \(
    generator row col = row * 10 + col;
    m = generate generator { rows = 2, columns = 3 };
    all id
       (map do row: all id
           (map do col: mat.at m row col == generator row col done [0..2])
            done [0..1])
),

"transposedEmpty-\(name)": \(
    compare (mat.size (mat.transposed (constMatrix 2 { rows = 0, columns = 0 }))) { columns = 0, rows = 0 } and
        compare (mat.size (mat.transposed (constMatrix 2 { rows = 0, columns = 4 }))) { columns = 0, rows = 4 } and
        compare (mat.size (mat.transposed (constMatrix 2 { rows = 4, columns = 0 }))) { columns = 4, rows = 0 }
),

"transposedSize-\(name)": \(
    compare (mat.size (mat.transposed (constMatrix 2 { rows = 3, columns = 4 }))) { columns = 3, rows = 4 }
),

"transposed-\(name)": \(
    generator row col = row * 10 + col;
    m = generate generator { rows = 2, columns = 3 };
    m' = mat.transposed m;
    all id
       (map do row: all id
           // like at test, but with col/row flipped
           (map do col: mat.at m' col row == generator row col done [0..2])
            done [0..1])
),

"transposed-back-\(name)": \(
    m = fromColumns [[1,4],[2,5],[3,6]];
    compareMatrices m (mat.transposed (mat.transposed m)) and
        not mat.equal m (mat.transposed m);
),

"flipped-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    m' = mat.flipped m;
    m'' = fromRows [[1,0,3],[4,5,6]];
    compareMatrices m m' and compareMatrices m m'' and compareMatrices m' m'';
),

"flipped-back-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    compareMatrices m (mat.flipped (mat.flipped m));
),

"flipped-empty-\(name)": \(
    m = constMatrix 2 { rows = 0, columns = 4 };
    compareMatrices (mat.flipped m) (mat.flipped (constMatrix 0 { rows = 0, columns = 4 }));
),

"toRowMajor-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    m' = mat.toRowMajor m;
    m'' = fromRows [[1,0,3],[4,5,6]];
    m''' = mat.toRowMajor m'';
    compareMatrices m m' and compareMatrices m m'' and compareMatrices m' m''
        and compareMatrices m m''';
),

"toColumnMajor-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    m' = mat.toColumnMajor m;
    m'' = fromColumns [[1,0,3],[4,5,6]];
    m''' = mat.toColumnMajor m'';
    compareMatrices m m' and compareMatrices m m'' and compareMatrices m' m''
        and compareMatrices m m''';
),

"diagonal-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    compare (vec.list (mat.getDiagonal 0 m)) [1,5] and
        compare (vec.list (mat.getDiagonal 1 m)) [4] and
        compare (vec.list (mat.getDiagonal (-1) m)) [0,6]
),

"scaled-\(name)": \(
    compareMatrices
       (mat.scaled 0.5 (constMatrix 2 { rows = 3, columns = 4 }))
       (constMatrix 1 { rows = 3, columns = 4 }) and
       compareMatrices
          (mat.scaled 0.5 (constMatrix (-3) { rows = 3, columns = 4 }))
          (constMatrix (-1.5) { rows = 3, columns = 4 }) and
       compareMatrices
          (mat.scaled 0.5 (constMatrix 2 { rows = 0, columns = 2 }))
          (constMatrix 5 { rows = 0, columns = 2 })
),

"mapRows-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    m' = fromColumns [[1,0,3],[4,5,6]];
    m'' = fromRows [[2,8],[0,10],[6,12]];
    compareMatrices (mat.mapRows (vec.scaled 2) m) m'' and
        compareMatrices (mat.mapRows (vec.scaled 2) m') m''
),

"mapRows-extend-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    m' = mat.mapRows do r: vec.concat [r, r] done m;
    compareMatrices m' (mat.concatHorizontal [ m, m ])
),

"mapRows-shrink-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    m' = mat.mapRows do r: vec.resizedTo 1 r done m;
    compareMatrices m' (fromRows [[1],[0],[3]]);
),

"mapRows-fail-\(name)": \(
    try
        m = fromRows [[1,4],[0,5],[3,6]];
        \() (mat.mapRows
            do r: 
                if vec.at r 0 == 1
                then vec.concat [r, r] 
                else vec.resizedTo 1 r
                fi 
            done m);
        false
    catch FailureException e:
        true
    yrt
),

"mapColumns-\(name)": \(
    m = fromRows [[1,4],[0,5],[3,6]];
    m' = fromColumns [[1,0,3],[4,5,6]];
    m'' = fromRows [[2,8],[0,10],[6,12]];
    compareMatrices (mat.mapColumns (vec.scaled 2) m) m'' and
        compareMatrices (mat.mapColumns (vec.scaled 2) m') m''
),

"mapColumns-extend-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    m' = mat.mapColumns do r: vec.concat [r, r] done m;
    compareMatrices m' (mat.concatVertical [ m, m ])
),

"mapColumns-shrink-\(name)": \(
    m = fromColumns [[1,4],[0,5],[3,6]];
    m' = mat.mapColumns do r: vec.resizedTo 1 r done m;
    compareMatrices m' (fromColumns [[1],[0],[3]]);
),

"mapColumns-fail-\(name)": \(
    try
        m = fromColumns [[1,4],[0,5],[3,6]];
        \() (mat.mapColumns
            do r: 
                if vec.at r 0 == 1
                then vec.concat [r, r] 
                else vec.resizedTo 1 r
                fi 
            done m);
        false
    catch FailureException e:
        true
    yrt
),

"minValue-\(name)": \(
    compare (mat.minValue (fromRows [[1,2],[3,4],[5,-1]])) (-1) and
    compare (mat.minValue (fromRows [[1,2],[3,0],[5,-1]])) (-1) and
    compare (mat.minValue (fromRows [[1,2],[3,0],[5,1]])) 0 and
    compare (mat.minValue (fromRows [[],[],[]])) 0
),    

"maxValue-\(name)": \(
    compare (mat.maxValue (fromRows [[1,2],[3,4],[5,-1]])) 5 and
    compare (mat.maxValue (fromRows [[1,2],[3,0],[5,-1]])) 5 and
    compare (mat.maxValue (fromRows [[-1,-2],[-3,0],[-5,-1]])) 0 and
    compare (mat.maxValue (fromRows [[-1,-2],[-3,-4],[-5,-1]])) (-1) and
    compare (mat.maxValue (fromRows [[],[],[]])) 0
),    

"total-\(name)": \(
    compare (mat.total (fromRows [[1,2],[3,4],[5,-1]])) 14 and
    compare (mat.total (fromRows [[1,2],[3,0],[5,-1]])) 10 and
    compare (mat.total (fromRows [[-1,-2],[-3,0],[-5,-1]])) (-12) and
    compare (mat.total (fromRows [[-1,-2],[-3,-4],[-5,-1]])) (-16) and
    compare (mat.total (fromRows [[],[],[]])) 0
),    

"sum-\(name)": \(
    compareMatrices
       (mat.sum [constMatrix 2 { rows = 3, columns = 4 },
                 constMatrix 1 { rows = 3, columns = 4 }])
       (constMatrix 3 { rows = 3, columns = 4 }) and
    compareMatrices
       (mat.sum [constMatrix 2 { rows = 3, columns = 4 },
                 constMatrix 1 { rows = 3, columns = 4 },
                 fromRows [[1,2,3,4],[5,6,7,8],[9,10,11,12]]])
       (fromRows [[4,5,6,7],[8,9,10,11],[12,13,14,15]])
),

"sumFail-\(name)": \(
    try 
      \() (mat.sum [constMatrix 2 { rows = 3, columns = 4 },
                    constMatrix 1 { rows = 3, columns = 5 }]);
        false;
    catch FailureException e:
        true
    yrt
),

"sparseSum-\(name)": \(
    s = mat.newSparseMatrix { rows = 2, columns = 3 }
       (Columns [
            { i = 0, j = 0, v = 1 },
            { i = 0, j = 2, v = 2 },
            { i = 1, j = 1, v = 4 },
        ]);
    t = mat.newSparseMatrix { rows = 2, columns = 3 }
        (Columns [
            { i = 0, j = 1, v = 7 },
            { i = 1, j = 0, v = 5 },
            { i = 1, j = 1, v = -4 }, // NB this means [1,1] -> 0, sparse zero
        ]);
    tot = mat.sum [s, t];
    mat.isSparse? tot and
        compareMatrices tot (mat.sum [mat.toDense s, t]) and
        compareMatrices tot (mat.sum [mat.toDense s, mat.toDense t]) and
        compareMatrices tot (mat.sum [s, mat.toDense t]) and
        compareMatrices tot 
           (mat.newSparseMatrix { rows = 2, columns = 3 } (Rows [
               { i = 0, j = 0, v = 1 },
               { i = 0, j = 1, v = 7 },
               { i = 0, j = 2, v = 2 },
               { i = 1, j = 0, v = 5 },
            ])) and
        compare (mat.density tot) (4/6)
),

"difference-\(name)": \(
    compareMatrices
       (mat.difference (constMatrix 2 { rows = 3, columns = 4 })
                       (constMatrix 1 { rows = 3, columns = 4 }))
       (constMatrix 1 { rows = 3, columns = 4 })
),

"differenceFail-\(name)": \(
    try 
      \() (mat.difference (constMatrix 2 { rows = 3, columns = 4 })
                          (constMatrix 1 { rows = 3, columns = 5 }));
        false;
    catch FailureException e:
        true
    yrt
),

"sparseDifference-\(name)": \(
    s = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = 0, j = 0, v = 1 },
        { i = 0, j = 2, v = 2 },
        { i = 1, j = 1, v = 4 },
    ]);
    t = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = 0, j = 1, v = 7 },
        { i = 1, j = 0, v = 5 },
        { i = 1, j = 1, v = 6 },
    ]);
    diff = mat.difference s t;
    mat.isSparse? diff and
        compareMatrices diff (mat.difference (mat.toDense s) t) and
        compareMatrices diff (mat.difference (mat.toDense s) (mat.toDense t)) and
        compareMatrices diff (mat.difference s (mat.toDense t)) and
        compareMatrices diff 
           (mat.newSparseMatrix { rows = 2, columns = 3 } (Rows [
               { i = 0, j = 0, v = 1 },
               { i = 0, j = 1, v = -7 },
               { i = 0, j = 2, v = 2 },
               { i = 1, j = 0, v = -5 },
               { i = 1, j = 1, v = -2 },
            ]))
),

"abs-\(name)": \(
    compareMatrices
       (mat.abs (fromColumns [[-1,4],[2,-5],[-3,0]]))
       (fromColumns [[1,4],[2,5],[3,0]])
),

"product-\(name)": \(
    compareMatrices
       (mat.product (constMatrix 2 { rows = 4, columns = 2 })
                    (constMatrix 3 { rows = 2, columns = 3 }))
       (constMatrix 12 { rows = 4, columns = 3 }) and
        compareMatrices
           (mat.product (fromColumns [[1,4],[2,5],[3,6]])
                        (fromColumns [[7,9,11],[8,10,12]]))
           (fromColumns [[58,139],[64,154]])
),

"entryWiseProduct-\(name)": \(
    compareMatrices
       (mat.entryWiseProduct
           [fromRows [[1,2,3],[4,5,0]],
            fromRows [[6,7,8],[0,1,2]]])
       (fromRows [[6,14,24],[0,5,0]]) and
    compareMatrices
       (mat.entryWiseProduct
           [fromRows [[1,2,3],[4,5,0]],
            fromColumns [[6,0],[7,1],[8,2]]])
       (fromRows [[6,14,24],[0,5,0]])
),

"entryWiseDivide-\(name)": \(
    compareMatrices
       (mat.entryWiseDivide
           (fromRows [[1,2,3],[4,5,0]])
           (fromRows [[6,7,8],[1,2,3]]))
       (fromRows [[1/6,2/7,3/8],[4,5/2,0]]) and
    compareMatrices
       (mat.entryWiseDivide
           (fromRows [[1,2,3],[4,5,0]])
           (fromColumns [[6,1],[7,2],[8,3]]))
       (fromRows [[1/6,2/7,3/8],[4,5/2,0]]);
),

"sparseProduct-\(name)": \(
    s = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = 0, j = 0, v = 1 },
        { i = 0, j = 2, v = 2 },
        { i = 1, j = 1, v = 4 },
    ]);
    t = mat.newSparseMatrix { rows = 3, columns = 2 } (Columns [
        { i = 0, j = 1, v = 7 },
        { i = 1, j = 0, v = 5 },
        { i = 2, j = 0, v = 6 },
    ]);
    prod = mat.product s t;
    mat.isSparse? prod and
        compareMatrices prod (mat.product (mat.toDense s) t) and
        compareMatrices prod (mat.product (mat.toDense s) (mat.toDense t)) and
        compareMatrices prod (mat.product s (mat.toDense t)) and
        compareMatrices prod 
           (mat.newSparseMatrix { rows = 2, columns = 2 } (Rows [
               { i = 0, j = 0, v = 12 },
               { i = 0, j = 1, v = 7 },
               { i = 1, j = 0, v = 20 },
            ]))
),

"productFail-\(name)": \(
    try
      \() (mat.product (constMatrix 2 { rows = 4, columns = 2 })
                       (constMatrix 3 { rows = 3, columns = 2 }));
        false;
    catch FailureException e:
        true
    yrt
),

"resizedTo-\(name)": \(
    compareMatrices
       (mat.resizedTo { rows = 2, columns = 2 }
           (fromColumns [[1,4],[2,5],[3,6]]))
       (fromColumns [[1,4],[2,5]]) and
        compareMatrices
           (mat.resizedTo { rows = 3, columns = 4 }
               (fromColumns [[1,4],[2,5],[3,6]]))
           (fromColumns [[1,4,0],[2,5,0],[3,6,0],[0,0,0]]) and
        compareMatrices
           (mat.resizedTo { rows = 1, columns = 1 }
               (fromColumns [[1,4],[2,5],[3,6]]))
           (fromRows [[1]]) and
        compareMatrices
           (mat.resizedTo { rows = 2, columns = 3 }
               (mat.zeroMatrix { rows = 0, columns = 0 }))
           (fromRows [[0,0,0],[0,0,0]]) and
        mat.isSparse?
           (mat.resizedTo { rows = 1, columns = 1 }
               (mat.toSparse (fromColumns [[1,4],[2,5],[3,6]])))
),

"tiledTo-\(name)": \(
    compareMatrices
       (mat.tiledTo { rows = 2, columns = 2 }
           (fromColumns [[1,4],[2,5],[3,6]]))
       (fromColumns [[1,4],[2,5]]) and
        compareMatrices
           (mat.tiledTo { rows = 3, columns = 4 }
               (fromColumns [[1,4],[2,5],[3,6]]))
           (fromColumns [[1,4,1],[2,5,2],[3,6,3],[1,4,1]]) and
        compareMatrices
           (mat.tiledTo { rows = 7, columns = 2 }
               (fromColumns [[1,4],[2,5],[3,6]]))
           (fromColumns [[1,4,1,4,1,4,1],[2,5,2,5,2,5,2]]) and
        compareMatrices
           (mat.tiledTo { rows = 1, columns = 1 }
               (fromColumns [[1,4],[2,5],[3,6]]))
           (fromRows [[1]]) and
        compareMatrices
           (mat.tiledTo { rows = 2, columns = 3 }
               (mat.zeroMatrix { rows = 0, columns = 0 }))
           (fromRows [[0,0,0],[0,0,0]]) and
        compareMatrices
           (mat.tiledTo { rows = 0, columns = 0 }
               (mat.zeroMatrix { rows = 4, columns = 3 }))
           (fromRows [])
),

"zeroSizeMatrix-\(name)": \(
    compareMatrices
       (mat.zeroMatrix { rows = 0, columns = 0 })
       (fromColumns []) and
        compareMatrices
           (mat.zeroMatrix { rows = 0, columns = 1 })
           (fromColumns [[]]) and
        (not mat.equal (fromColumns [[]])
                       (fromRows [[]])) and
        compareMatrices
           (mat.zeroMatrix { rows = 0, columns = 0 })
           (mat.newSparseMatrix { rows = 0, columns = 0 } (Columns [])) and
        compareMatrices
           (mat.zeroMatrix { rows = 1, columns = 0 })
           (mat.newSparseMatrix { rows = 1, columns = 0 } (Columns []))
),

"asRows-\(name)": \(
    compare
       (map vec.list
           (mat.asRows (fromColumns [[1,4],[0,5],[3,6]])))
        [[1,0,3],[4,5,6]];
),

"asColumns-\(name)": \(
    compare
       (map vec.list
           (mat.asColumns (fromColumns [[1,4],[0,5],[3,6]])))
        [[1,4],[0,5],[3,6]];
),

"repeated-horiz-\(name)": \(
    compareMatrices
       (mat.repeatedHorizontal 2 (fromColumns [[1,4],[0,5]]))
       (fromColumns [[1,4],[0,5],[1,4],[0,5]]) and
    compareMatrices
       (mat.repeatedHorizontal 2 (fromRows [[1,0],[4,5]]))
       (fromColumns [[1,4],[0,5],[1,4],[0,5]]) and
    compareMatrices
       (mat.repeatedHorizontal 0 (fromColumns [[1,4],[0,5]]))
       (fromColumns []) and
    compareMatrices
       (mat.repeatedHorizontal 4 (fromColumns [[]]))
       (fromColumns [[],[],[],[]])
),

"repeated-vert-\(name)": \(
    compareMatrices
       (mat.repeatedVertical 2 (fromRows [[1,4],[0,5]]))
       (fromRows [[1,4],[0,5],[1,4],[0,5]]) and
    compareMatrices
       (mat.repeatedVertical 2 (fromColumns [[1,0],[4,5]]))
       (fromRows [[1,4],[0,5],[1,4],[0,5]]) and
    compareMatrices
       (mat.repeatedVertical 0 (fromRows [[1,4],[0,5]]))
       (fromRows []) and
    compareMatrices
       (mat.repeatedVertical 4 (fromRows [[]]))
       (fromRows [[],[],[],[]])
),

"concat-horiz-\(name)": \(
    compareMatrices
       (mat.concatHorizontal 
          [(fromColumns [[1,4],[0,5]]),
           (fromRows [[3],[6]])])
       (fromColumns [[1,4],[0,5],[3,6]])
),

"concatEmpty-horiz-\(name)": \(
    compareMatrices
       (mat.concatHorizontal 
          [(fromColumns [[]]),
           (fromColumns [[],[]]),
           (mat.zeroMatrix { rows = 0, columns = 6 })])
       (mat.zeroMatrix { rows = 0, columns = 9 }) and
       compareMatrices
          (mat.concatHorizontal 
             [(fromRows [[]]),
              (fromRows [[1,2]]),
              (mat.zeroMatrix { rows = 1, columns = 0 })])
          (fromRows [[1,2]])
),

"sparseConcat-horiz-\(name)": \(
    s = mat.concatHorizontal 
          [mat.toSparse (fromColumns [[1,4],[0,5]]),
           mat.toSparse (fromRows [[3],[6]])];
    compareMatrices s (fromColumns [[1,4],[0,5],[3,6]]) and
        compare (mat.isSparse? s) true and
        compare (mat.density s) (5/6)
),

"concatFail-horiz-\(name)": \(
    try
        \() (mat.concatHorizontal 
          [(fromColumns [[1,4],[0,5]]),
           (fromColumns [[3],[6]])]);
        false
    catch FailureException e:
        true
    yrt
),

"concat-vert-\(name)": \(
    compareMatrices
       (mat.concatVertical 
          [(fromColumns [[1,4],[0,5]]),
           (fromRows [[3,6]])])
       (fromColumns [[1,4,3],[0,5,6]])
),

"sparseConcat-vert-\(name)": \(
    s = mat.concatVertical 
          [mat.toSparse (fromColumns [[1,4],[0,5]]),
           mat.toSparse (fromRows [[3,6]])];
    compareMatrices s (fromColumns [[1,4,3],[0,5,6]]) and
        compare (mat.isSparse? s) true and
        compare (mat.density s) (5/6)
),

"concatFail-vert-\(name)": \(
    try
        \() (mat.concatVertical 
          [(fromColumns [[1,4],[0,5]]),
           (fromRows [[3],[6]])]);
        false
    catch FailureException e:
        true
    yrt
),

"rowSlice-\(name)": \(
    compareMatrices
       (mat.rowSlice (fromRows [[1,0],[3,4],[0,6],[7,8]]) 1 3)
       (fromRows [[3,4],[0,6]]) and
        compareMatrices
           (mat.rowSlice (fromRows [[1,0],[3,4],[0,6],[7,8]]) 3 6)
           (fromRows [[7,8]])
),

"columnSlice-\(name)": \(
    compareMatrices
       (mat.columnSlice (fromRows [[1,0,3,4],[0,6,7,8]]) 1 3)
       (fromRows [[0,3],[6,7]]) and
        compareMatrices
           (mat.columnSlice (fromRows [[1,0,3,4],[0,6,7,8]]) 2 5)
           (fromRows [[3,4],[7,8]])
),

"density-\(name)": \(
    compare (mat.density (fromColumns [[1,2,0],[0,5,0]])) (3/6) and
        compare (mat.density (fromColumns [[1,2,3],[4,5,6]])) (6/6) and
        compare (mat.density (fromColumns [[0,0,0],[0,0,0]])) 0
),

"nonZeroValues-\(name)": \(
    compare (mat.nonZeroValues (fromColumns [[1,2,0],[0,5,0]])) 3 and
        compare (mat.nonZeroValues (fromColumns [[1,2,3],[4,5,6]])) 6 and
        compare (mat.nonZeroValues (fromColumns [[0,0,0],[0,0,0]])) 0
),

"toSparse-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    compareMatrices (mat.toSparse m) m and
        compareMatrices (mat.toDense (mat.toSparse m)) m and
        compare (mat.density (mat.toSparse m)) (6/9)
),

"toDense-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    compareMatrices (mat.toDense m) m and
        compareMatrices (mat.toSparse (mat.toDense m)) m
),

"filter-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    compareMatrices
       (mat.filter (> 2) m)
       (fromColumns [[0,0,0],[0,0,6],[0,0,3]]) and
        compare (mat.isSparse? (mat.filter (> 2) m)) true and
        compare (mat.density (mat.filter (> 2) m)) (2/9)
),

"all-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    compare (mat.all (== 9) m) false and
    compare (mat.all (!= 9) m) true and
    compare (mat.all (== 2) m) false and
    compare (mat.all (!= 2) m) false
),

"any-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    compare (mat.any (== 9) m) false and
    compare (mat.any (!= 9) m) true and
    compare (mat.any (== 2) m) true and
    compare (mat.any (!= 2) m) true
),

"newSparseMatrix-\(name)": \(
    s = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = 0, j = 0, v = 1 },
        { i = 0, j = 2, v = 2 },
        { i = 1, j = 1, v = 4 },
    ]);
    // If there are zeros in the entries list, they should not end up
    // in the sparse data
    t = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = 0, j = 0, v = 1 },
        { i = 0, j = 2, v = 0 },
        { i = 1, j = 1, v = 4 },
    ]);
    // Any out-of-range or non-integer i, j should be ignored too
    u = mat.newSparseMatrix { rows = 2, columns = 3 } (Columns [
        { i = -1, j = 0, v = 1 },
        { i = 0, j = 4, v = 3 },
        { i = 1, j = 1.5, v = 4 },
    ]);
    compare (mat.density s) (3/6) and
        compare (mat.density t) (2/6) and
        compareMatrices s (fromRows [[1,0,2],[0,4,0]]) and
        compareMatrices t (fromRows [[1,0,0],[0,4,0]]) and
        compareMatrices u (fromRows [[0,0,0],[0,0,0]])
),

"enumerate-\(name)": \(
    m = fromColumns [[1,2,0],[-1,-4,6],[0,0,3]];
    all = [
        { i = 0, j = 0, v = 1 },
        { i = 1, j = 0, v = 2 },
        { i = 2, j = 0, v = 0 },
        { i = 0, j = 1, v = -1 },
        { i = 1, j = 1, v = -4 },
        { i = 2, j = 1, v = 6 },
        { i = 0, j = 2, v = 0 },
        { i = 1, j = 2, v = 0 },
        { i = 2, j = 2, v = 3 },
    ];
    sortEntries = 
        sortBy do a b:
            if a.i == b.i then a.j < b.j else a.i < b.i fi
        done;
    compare
       (sortEntries (mat.enumerate m))
       (sortEntries 
           (if mat.isSparse? m then filter do d: d.v != 0 done all else all fi));
),

]);

colhash = makeTests "column-dense" id;
rowhash = makeTests "row-dense" mat.flipped;
sparsecolhash = makeTests "column-sparse" mat.toSparse;

// there are two possible orders for constructing a sparse row-major
// matrix from a dense col-major one, so test them both:
sparserowhash1 = makeTests "row-sparse-a" (mat.toSparse . mat.flipped);
sparserowhash2 = makeTests "row-sparse-b" (mat.flipped . mat.toSparse);

all = [:];
for [ colhash, rowhash, sparsecolhash, sparserowhash1, sparserowhash2 ] do h:
    for (keys h) do k: all[k] := h[k] done;
done;

all is hash<string, () -> boolean>;