// 3rd_party_lib:matrix4cj/target/matrix4cj
// 3rd_party_lib_ohos:matrix4cj/target/aarch64-linux-ohos/matrix4cj
package matrix4cj.tests.HLT.LEVEL1

import matrix4cj.*
import std.math.*
import std.unittest.*
import std.unittest.testmacro.*

@Test
public class TestLU {
    @TestCase
    func L1_Test_LU_Det_01(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 2.0, 3.0],
                [4.0, 5.0, 6.0],
                [7.0, 8.0, 9.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var value = Lu01.det()
        @Assert(abs(value-Float64(0.0))<1e-6,true)
    }
    @TestCase
    func L1_Test_LU_Det_02(): Unit {
        var matrix01 = Matrix(
            [
                [0.0, 2.0, 3.0],
                [4.0, 5.0, 6.0],
                [7.0, 8.0, 9.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var value = Lu01.det()
        @Assert(abs(value-Float64(3.0))<1e-6,true)
    }
    @TestCase
    func L1_Test_LU_Det_03(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0],
                [0.0, 1.0, 0.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var value = Lu01.det()
        @Assert(abs(value-Float64(-1.0))<1e-6,true)
    }
    @TestCase
    func L1_Test_LU_Det_04(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )

        var Lu01 = LUDecomposition(matrix01)
        var value = Lu01.det()
        @Assert(abs(value-Float64(1.0))<1e-6,true)
    }
    @TestCase
    func L1_Test_LU_Det_05(): Unit {
        var matrix01 = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var value = Lu01.det()
        @Assert(abs(value-Float64(0.0))<1e-6,true)
    }
    @TestCase
    func L1_Test_LU_Function_01(): Unit {
        var A_matrix = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_L = A_matrix_LU.getL()
        var A_matrix_LU_U = A_matrix_LU.getU()
        var LU_Matrix = A_matrix_LU_L * A_matrix_LU_U
        var A_matrix_LU_P = createPivotMatrix(A_matrix_LU.getPivot(), A_matrix.rowNum)
        var PLU = A_matrix_LU_P * LU_Matrix
        @Assert(PLU.rowNum,A_matrix.rowNum)
        @Assert(PLU.colNum,A_matrix.colNum)
        var rows = PLU.rowNum
        var cols = PLU.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(PLU.get(i,j)-A_matrix.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getDoublePivot_01(): Unit {
        var matrix01 = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getDoublePivot()
        var expected_piv: Array<Float64> = [Float64(2.0), Float64(0.0), Float64(3.0), Float64(1.0)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getDoublePivot_02(): Unit {
        var matrix01 = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [3.0, 7.0, 5.0, 1.0],
                [1.0, 5.0, 9.0, 2.0],
                [5.0, 1.0, 2.0, 6.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getDoublePivot()
        var expected_piv: Array<Float64> = [Float64(0.0), Float64(1.0), Float64(2.0), Float64(3.0)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getDoublePivot_03(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getDoublePivot()
        var expected_piv: Array<Float64> = [Float64(0.0), Float64(1.0), Float64(2.0), Float64(3.0)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getDoublePivot_04(): Unit {
        var matrix01 = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getDoublePivot()
        var expected_piv: Array<Float64> = [Float64(0.0), Float64(1.0), Float64(2.0), Float64(3.0)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getL_01(): Unit {
        var A_matrix = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_L = A_matrix_LU.getL()

        var expected_L = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.2857142857142857, 1.0, 0.0, 0.0],
                [0.7142857142857143, 0.11999999999999994, 1.0, 0.0],
                [0.7142857142857143, -0.44, -0.4615384615384619, 1.0]
            ]
        )
        var rows = A_matrix_LU_L.rowNum
        var cols = A_matrix_LU_L.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(expected_L.get(i,j)-A_matrix_LU_L.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getL_02(): Unit {
        var A_matrix = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [3.0, 7.0, 5.0, 1.0],
                [1.0, 5.0, 9.0, 2.0],
                [5.0, 1.0, 2.0, 6.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_L = A_matrix_LU.getL()

        var expected_L = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.3333333333333333, 1.0, 0.0, 0.0],
                [0.1111111111111111, 0.7777777777777778, 1.0, 0.0],
                [0.5555555555555556, -0.11111111111111112, 0.3732394366197183, 1.0]
            ]
        )
        var rows = A_matrix_LU_L.rowNum
        var cols = A_matrix_LU_L.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(expected_L.get(i,j)-A_matrix_LU_L.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getL_03(): Unit {
        var A_matrix = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_L = A_matrix_LU.getL()
        var rows = A_matrix_LU_L.rowNum
        var cols = A_matrix_LU_L.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(A_matrix.get(i,j)-A_matrix_LU_L.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getL_04(): Unit {
        var A_matrix = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_L = A_matrix_LU.getL()

        var expected_L = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var rows = A_matrix_LU_L.rowNum
        var cols = A_matrix_LU_L.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(expected_L.get(i,j)-A_matrix_LU_L.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getPivot_01(): Unit {
        var matrix01 = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [3.0, 7.0, 5.0, 1.0],
                [1.0, 5.0, 9.0, 2.0],
                [5.0, 1.0, 2.0, 6.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getPivot()
        var expected_piv: Array<Int64> = [Int64(0), Int64(1), Int64(2), Int64(3)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getPivot_02(): Unit {
        var matrix01 = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getPivot()
        var expected_piv: Array<Int64> = [Int64(2), Int64(0), Int64(3), Int64(1)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getPivot_03(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getPivot()
        var expected_piv: Array<Int64> = [Int64(0), Int64(1), Int64(2), Int64(3)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getPivot_04(): Unit {
        var matrix01 = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var Lu01 = LUDecomposition(matrix01)
        var LU_P = Lu01.getPivot()
        var expected_piv: Array<Int64> = [Int64(0), Int64(1), Int64(2), Int64(3)]
        @Assert(expected_piv,LU_P)
    }
    @TestCase
    func L1_Test_LU_getU_01(): Unit {
        var A_matrix = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [3.0, 7.0, 5.0, 1.0],
                [1.0, 5.0, 9.0, 2.0],
                [5.0, 1.0, 2.0, 6.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_U = A_matrix_LU.getU()

        var expected_U = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [0.0, 6.0, 4.666666666666667, -0.6666666666666665],
                [0.0, 0.0, 5.2592592592592595, 1.9629629629629628],
                [0.0, 0.0, 0.0, 2.415492957746479]
            ]
        )
        var rows = A_matrix_LU_U.rowNum
        var cols = A_matrix_LU_U.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(expected_U.get(i,j)-A_matrix_LU_U.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getU_02(): Unit {
        var A_matrix = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_U = A_matrix_LU.getU()

        var expected_U = Matrix(
            [
                [7.0, 5.0, 6.0, 6.0],
                [0.0, 3.5714285714285716, 6.285714285714286, 5.285714285714286],
                [0.0, 0.0, -1.0399999999999991, 3.08],
                [0.0, 0.0, 0.0, 7.461538461538463]
            ]
        )
        var rows = A_matrix_LU_U.rowNum
        var cols = A_matrix_LU_U.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(expected_U.get(i,j)-A_matrix_LU_U.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getU_03(): Unit {
        var A_matrix = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_U = A_matrix_LU.getU()
        var rows = A_matrix_LU_U.rowNum
        var cols = A_matrix_LU_U.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(A_matrix.get(i,j)-A_matrix_LU_U.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_getU_04(): Unit {
        var A_matrix = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var A_matrix_LU = LUDecomposition(A_matrix)
        var A_matrix_LU_U = A_matrix_LU.getU()
        var rows = A_matrix_LU_U.rowNum
        var cols = A_matrix_LU_U.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(A_matrix.get(i,j)-A_matrix_LU_U.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_isNonsingular_01(): Unit {
        var A_matrix = Matrix(
            [
                [1.0, 2.0, 3.0],
                [4.0, 5.0, 6.0],
                [7.0, 8.0, 9.0]
            ]
        )
        var LU_Matrix = A_matrix.lu()
        @Assert(LU_Matrix.isNonsingular(),false)
    }
    @TestCase
    func L1_Test_LU_isNonsingular_02(): Unit {
        var A_matrix = Matrix(
            [
                [0.0, 2.0, 3.0],
                [4.0, 5.0, 6.0],
                [7.0, 8.0, 9.0]
            ]
        )
        var LU_Matrix = A_matrix.lu()
        @Assert(LU_Matrix.isNonsingular(),true)
    }
    @TestCase
    func L1_Test_LU_isNonsingular_03(): Unit {
        var A_matrix = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var LU_Matrix = A_matrix.lu()
        @Assert(LU_Matrix.isNonsingular(),true)
    }
    @TestCase
    func L1_Test_LU_isNonsingular_04(): Unit {
        var A_matrix = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var LU_Matrix = A_matrix.lu()
        @Assert(LU_Matrix.isNonsingular(),false)
    }
    @TestCase
    func L1_Test_LU_solve_01(): Unit {
        var matrix01 = Matrix(
            [
                [9.0, 3.0, 1.0, 5.0],
                [3.0, 7.0, 5.0, 1.0],
                [1.0, 5.0, 9.0, 2.0],
                [5.0, 1.0, 2.0, 6.0]
            ]
        )
        var A_Matrix = LUDecomposition(matrix01)
        var B_Matrix = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var X_Matrix = A_Matrix.solve(B_Matrix)
        var expected_X_Matrix = Matrix(
            [
                [-0.7536443148688047, 0.7361516034985423, 1.7871720116618073, -0.7040816326530611],
                [0.7332361516034984, -0.6137026239067055, -1.3790087463556848, 1.5612244897959184],
                [0.16909620991253646, 0.8425655976676384, 1.4752186588921279, -0.5306122448979591],
                [1.282798833819242, -0.12536443148688048, -1.084548104956268, 1.8367346938775508]
            ]
        )
        @Assert(X_Matrix.rowNum,B_Matrix.rowNum)
        @Assert(X_Matrix.colNum,B_Matrix.colNum)
        var rows = X_Matrix.rowNum
        var cols = X_Matrix.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(X_Matrix.get(i,j)-expected_X_Matrix.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_solve_02(): Unit {
        var matrix01 = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var A_Matrix = LUDecomposition(matrix01)
        var B_Matrix = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var X_Matrix = A_Matrix.solve(B_Matrix)
        var expected_X_Matrix = Matrix(
            [
                [-0.08247422680412367, 0.18556701030927833, 0.24742268041237114, -0.29896907216494867],
                [-0.2680412371134022, -0.8969072164948456, -0.1958762886597939, 1.2783505154639183],
                [0.26804123711340216, 0.3969072164948456, 0.1958762886597939, -0.778350515463918],
                [0.05154639175257731, 0.134020618556701, -0.154639175257732, 0.06185567010309282]
            ]
        )
        @Assert(X_Matrix.rowNum,B_Matrix.rowNum)
        @Assert(X_Matrix.colNum,B_Matrix.colNum)
        var rows = X_Matrix.rowNum
        var cols = X_Matrix.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(X_Matrix.get(i,j)-expected_X_Matrix.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_solve_03(): Unit {
        var matrix01 = Matrix(
            [
                [2.0, 5.0, 8.0, 7.0],
                [5.0, 2.0, 2.0, 8.0],
                [7.0, 5.0, 6.0, 6.0],
                [5.0, 4.0, 4.0, 8.0]
            ]
        )
        var A_Matrix = LUDecomposition(matrix01)
        var B_Matrix = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var X_Matrix = A_Matrix.solve(B_Matrix)
        var AX = matrix01 * X_Matrix
        @Assert(AX.rowNum,B_Matrix.rowNum)
        @Assert(AX.colNum,B_Matrix.colNum)
        var rows = AX.rowNum
        var cols = AX.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(AX.get(i,j)-B_Matrix.get(i,j))<1e-6,true)
            }
        }
    }
    @TestCase
    func L1_Test_LU_solve_05(): Unit {
        var matrix01 = Matrix(
            [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]
            ]
        )
        var A_Matrix = LUDecomposition(matrix01)
        var B_Matrix = Matrix(
            [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0]
            ]
        )
        var X_Matrix = A_Matrix.solve(B_Matrix)
        @Assert(X_Matrix.rowNum,B_Matrix.rowNum)
        @Assert(X_Matrix.colNum,B_Matrix.colNum)
        var rows = X_Matrix.rowNum
        var cols = X_Matrix.colNum
        for (i in 0..rows) {
            for (j in 0..cols) {
                @Assert(abs(X_Matrix.get(i,j)-B_Matrix.get(i,j))<1e-6,true)
            }
        }
    }
}

public func createPivotMatrix(pivot: Array<Int64>, size: Int64): Matrix {
    var P = Matrix(size, size)
    for (i in 0..size) {
        P.set(size - i - 1, pivot[i], 1.0);
    }
    return P;
}