у меня есть такие классы: package com.cgvsu.math;


public class Matrix3x3 extends AbstractMatrix {
    private static final int SIZE = 3;
    private float[][] elements;

    // Конструкторы + getters and setters
    public Matrix3x3(float[] elements) {
        // Надо ли обрабатывать и отслеживать ошибки, по типу: ввели матрицу не 3на 3.... пупупу... ну... это наш модуль, так что, дума.ю нет
        // надо у Борисова узнать
        if (elements.length != SIZE * SIZE) {
            throw new IllegalArgumentException("Массив должен содержать ровно " + (SIZE * SIZE) + " элементов.");
        }
        this.elements = new float[SIZE][SIZE];
        int k = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                this.elements[i][j] = elements[k];
            }
        }
    }

    public Matrix3x3(int one) {
        //Опять вопрос к Борисову: проверять ли это num на какое-то значение, отличное от нуля, или нет... а, хотя, я наебу систему
        this.elements = new float[SIZE][SIZE];
        for (int i = 0; i < SIZE; i++) {
            this.elements[i][i] = 1;
        }
    }

    public Matrix3x3() {
        this.elements = new float[SIZE][SIZE];
    }

    @Override
    public Matrix3x3 add(AbstractMatrix other) {
        float[] a = new float[9];
        int k = 0;
        if (!isMatrix3x3(other)) {
            throw new IllegalArgumentException("Invalid matrix type for dot product");
        }
        Matrix3x3 o = (Matrix3x3) other;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                a[k] = this.elements[i][j] + o.elements[i][j];
            }
        }
        return new Matrix3x3(a);
    }

    @Override
    public Matrix3x3 subtract(AbstractMatrix other) {
        float[] a = new float[9];
        int k = 0;
        if (!isMatrix3x3(other)) {
            throw new IllegalArgumentException("Invalid matrix type for dot product");
        }
        Matrix3x3 o = (Matrix3x3) other;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                a[k] = this.elements[i][j] - o.elements[i][j];
            }
        }
        return new Matrix3x3(a);
    }

    // умножение матрицы на столбец - получаем столбец
    @Override
    public Vector3f multiply(AbstractVector other) {
        if (!isVector3f(other)) {
            throw new IllegalArgumentException("Invalid vector type for dot product");
        }
        Vector3f o = (Vector3f) other;
        Vector3f result = new Vector3f();
        for (int i = 0; i < SIZE; i++) {
            float res = 0;
            for (int j = 0; j < SIZE; j++) {
                res += (elements[i][j] * o.getNum(j));
            }
            result.setNum(i, res);
        }
        return result;
    }

    @Override
    public Matrix3x3 multiply(AbstractMatrix other) {
        if (!isMatrix3x3(other)) {
            throw new IllegalArgumentException("Invalid vector type for dot product");
        }
        Matrix3x3 o = (Matrix3x3) other;
        Matrix3x3 result = new Matrix3x3();
        for (int i = 0; i < SIZE; i++) {
            for (int k = 0; k < SIZE; k++) {
                float res = 0;
                for (int j = 0; j < SIZE; j++) {
                    res += this.elements[i][j] * o.elements[j][k];
                }
                result.elements[i][k] = res;
            }
        }
        return result;
    }

    // транспонирование матрицы
    @Override
    public void transposition() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = i + 1; j < SIZE; j++) {
                float temp = elements[i][j];
                elements[i][j] = elements[j][i];
                elements[j][i] = temp;
            }
        }
    }

    // определитель
    @Override
    public float determinant() {
        return elements[0][0] * (elements[1][1] * elements[2][2] - elements[1][2] * elements[2][1])
                - elements[0][1] * (elements[1][0] * elements[2][2] - elements[1][2] * elements[2][0])
                + elements[0][2] * (elements[1][0] * elements[2][1] - elements[1][1] * elements[2][0]);
    }

    /**
     * Вычисление обратной матрицы 3x3
     *
     * @return Обратная матрица 3x3
     * @throws ArithmeticException если матрица вырождена и не имеет обратной
     */
    @Override
    public Matrix3x3 inverse() {
        float det = determinant();
        if (det == 0) {
            throw new ArithmeticException("Матрица вырождена и не имеет обратной.");
        }

       Matrix3x3 tilda = computeTildaMatrix();
        float[] inverseElements = new float[9];
        int k = 0;
        for (int i = 0; i < SIZE; i++) {
            for(int j = 0; j < SIZE; j++, k++) {
                inverseElements[k] = tilda.elements[i][j] / det;
            }
        }

        return new Matrix3x3(inverseElements);
    }

    // Вычисление матрицы алгебраических дополнений для матрицы 3x3
    private float[][] computeDopMatrix() {
        float[][] dop = new float[SIZE][SIZE];

        dop[0][0] =  (elements[1][1] * elements[2][2] - elements[1][2] * elements[2][1]);
        dop[0][1] = -(elements[1][0] * elements[2][2] - elements[1][2] * elements[2][0]);
        dop[0][2] =  (elements[1][0] * elements[2][1] - elements[1][1] * elements[2][0]);

        dop[1][0] = -(elements[0][1] * elements[2][2] - elements[0][2] * elements[2][1]);
        dop[1][1] =  (elements[0][0] * elements[2][2] - elements[0][2] * elements[2][0]);
        dop[1][2] = -(elements[0][0] * elements[2][1] - elements[0][1] * elements[2][0]);

        dop[2][0] =  (elements[0][1] * elements[1][2] - elements[0][2] * elements[1][1]);
        dop[2][1] = -(elements[0][0] * elements[1][2] - elements[0][2] * elements[1][0]);
        dop[2][2] =  (elements[0][0] * elements[1][1] - elements[0][1] * elements[1][0]);

        return dop;
    }



    private Matrix3x3 computeTildaMatrix() {
        float[][] cofactors = computeDopMatrix();
        Matrix3x3 adjugate = new Matrix3x3();
        adjugate.elements = cofactors;

        // Транспонирование матрицы кофакторов
        adjugate.transposition();

        return adjugate;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (float[] row : elements) {
            for (float elem : row) {
                sb.append(String.format("%.2f\t", elem));
            }
            sb.append("\n");
        }
        boolean a = false;
        return sb.toString();
    }

    private boolean isMatrix3x3(AbstractMatrix other) {
        return other instanceof Matrix3x3;
    }

    private boolean isVector3f(AbstractVector other) {
        return other instanceof Vector3f;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Matrix3x3)) return false;
        Matrix3x3 other = (Matrix3x3) obj;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (Float.compare(this.elements[i][j], other.elements[i][j]) != 0) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public int hashCode() {
        int result = 1;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                result = 31 * result + Float.hashCode(elements[i][j]);
            }
        }
        return result;
    }

    // Геттер для элементов матрицы
    public float[][] getElements() {
        return elements;
    }
}
package com.cgvsu.math;

public class Matrix4x4 extends AbstractMatrix {
    private static final int SIZE = 4;
    private float[][] elements;

    // Конструкторы + getters and setters
    public Matrix4x4(float[] elements) {
        if (elements.length != SIZE * SIZE) {
            throw new IllegalArgumentException("Массив должен содержать ровно " + (SIZE * SIZE) + " элементов.");
        }
        this.elements = new float[SIZE][SIZE];
        int k = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                this.elements[i][j] = elements[k];
            }
        }
    }

    public Matrix4x4(int one) {
        //Опять вопрос к Борисову: проверять ли это num на какое-то значение, отличное от нуля, или нет... а, хотя, я наебу систему
        this.elements = new float[SIZE][SIZE];
        for (int i = 0; i < SIZE; i++) {
            this.elements[i][i] = 1;
        }
    }

    public Matrix4x4() {
        this.elements = new float[SIZE][SIZE];
    }

    @Override
    public Matrix4x4 add(AbstractMatrix other) {
        float[] a = new float[16];
        int k = 0;
        if (!isMatrix4x4(other)) {
            throw new IllegalArgumentException("Invalid matrix type for dot product");
        }
        Matrix4x4 o = (Matrix4x4) other;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                a[k] = this.elements[i][j] + o.elements[i][j];
            }
        }
        return new Matrix4x4(a);
    }

    @Override
    public Matrix4x4 subtract(AbstractMatrix other) {
        float[] a = new float[16];
        int k = 0;
        if (!isMatrix4x4(other)) {
            throw new IllegalArgumentException("Invalid matrix type for dot product");
        }
        Matrix4x4 o = (Matrix4x4) other;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                a[k] = this.elements[i][j] - o.elements[i][j];
            }
        }
        return new Matrix4x4(a);
    }

    @Override
    public Vector4f multiply(AbstractVector other) {
        if (!isVector4f(other)) {
            throw new IllegalArgumentException("Invalid vector type for dot product");
        }
        Vector4f o = (Vector4f) other;
        Vector4f result = new Vector4f();
        for (int i = 0; i < SIZE; i++) {
            float res = 0;
            for (int j = 0; j < SIZE; j++) {
                res += (elements[i][j] * o.getNum(j));
            }
            result.setNum(i, res);
        }
        return result;
    }

    @Override
    public Matrix4x4 multiply(AbstractMatrix other) {
        if (!isMatrix4x4(other)) {
            throw new IllegalArgumentException("Invalid vector type for dot product");
        }
        Matrix4x4 o = (Matrix4x4) other;
        Matrix4x4 result = new Matrix4x4();
        for (int i = 0; i < SIZE; i++) {
            for (int k = 0; k < SIZE; k++) {
                float res = 0;
                for (int j = 0; j < SIZE; j++) {
                    res += this.elements[i][j] * o.elements[j][k];
                }
                result.elements[i][k] = res;
            }
        }
        return result;
    }

    @Override
    public void transposition() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = i + 1; j < SIZE; j++) {
                float temp = elements[i][j];
                elements[i][j] = elements[j][i];
                elements[j][i] = temp;
            }
        }
    }

    @Override
    // Вычисление определителя матрицы 4x4
    public float determinant() {
        float det = 0;
        for (int col = 0; col < SIZE; col++) {
            det += (col % 2 == 0 ? 1 : -1) * elements[0][col] * getMinorMatrix(0, col).determinant();
        }
        return det;
    }

    /**
     * Вычисление матрицы алгебраических дополнений для матрицы 4x4
     *
     * @return Матрица алгебраических дополнений 4x4
     */
    private float[][] computeDopMatrix() {
        float[][] cofactors = new float[SIZE][SIZE];
        for (int row = 0; row < SIZE; row++) {
            for (int col = 0; col < SIZE; col++) {
                Matrix3x3 minorMatrix = getMinorMatrix(row, col);
                float minorDeterminant = minorMatrix.determinant();
                cofactors[row][col] = ((row + col) % 2 == 0 ? 1 : -1) * minorDeterminant;
            }
        }
        return cofactors;
    }

    /**
     * Вычисление матрицы тильда для матрицы 4x4
     *
     * @return Матрица присоединённых 4x4
     */
    private Matrix4x4 computeTildaMatrix() {
        float[][] cofactors = computeDopMatrix();
        Matrix4x4 tilda = new Matrix4x4();
        tilda.elements = cofactors;

        // Транспонирование матрицы кофакторов
        tilda.transposition();

        return tilda;
    }

    /**
     * Получение минорной матрицы 3x3, исключая указанную строку и столбец
     *
     * @param rowToExclude Строка для исключения
     * @param colToExclude Столбец для исключения
     * @return Минорная матрица 3x3
     */
    private Matrix3x3 getMinorMatrix(int rowToExclude, int colToExclude) {
        float[] minorElements = new float[9];
        int index = 0;
        for (int i = 0; i < SIZE; i++) {
            if (i == rowToExclude) continue;
            for (int j = 0; j < SIZE; j++) {
                if (j == colToExclude) continue;
                minorElements[index++] = elements[i][j];
            }
        }
        return new Matrix3x3(minorElements);
    }



    /**
     * Вычисление обратной матрицы 4x4
     *
     * @return Обратная матрица 4x4
     * @throws ArithmeticException если матрица вырождена и не имеет обратной
     */
    @Override
    public Matrix4x4 inverse() {
        float det = determinant();
        if (det == 0) {
            throw new ArithmeticException("Матрица вырождена и не имеет обратной.");
        }
        Matrix4x4 tilda = computeTildaMatrix();
        float[] inverseElements = new float[16];
        int k = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++, k++) {
                inverseElements[k] = tilda.elements[i][j] / det;
            }
        }
        return new Matrix4x4(inverseElements);
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (float[] row : elements) {
            for (float elem : row) {
                sb.append(String.format("%.2f\t", elem));
            }
            sb.append("\n");
        }
        boolean a = false;
        return sb.toString();
    }

    private boolean isMatrix4x4(AbstractMatrix other) {
        return other instanceof Matrix4x4;
    }

    private boolean isVector4f(AbstractVector other) {
        return other instanceof Vector4f;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Matrix4x4)) return false;
        Matrix4x4 other = (Matrix4x4) obj;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (Float.compare(this.elements[i][j], other.elements[i][j]) != 0) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public int hashCode() {
        int result = 1;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                result = 31 * result + Float.hashCode(elements[i][j]);
            }
        }
        return result;
    }

    // Геттер для элементов матрицы
    public float[][] getElements() {
        return elements;
    }
}
мне надо написать тесты, проверяющие корректность inverse(). вот пока какие тесты у меня есть: package com.cgvsu.math.tests;

import com.cgvsu.math.AbstractVector;
import com.cgvsu.math.Matrix4x4;
import com.cgvsu.math.Matrix3x3;
import com.cgvsu.math.Vector4f;
import com.cgvsu.math.Vector3f;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class Matrix4x4Test {

    // Тестирование конструктора с правильным размером массива
    @Test
    public void testConstructorWithValidArray() {
        float[] elements = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        float[][] expected = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 16}
        };
        Assertions.assertArrayEquals(expected, matrix.getElements(),
            "Матрица должна быть создана из переданного массива");
    }

    // Тестирование конструктора с неверным размером массива
    @Test
    public void testConstructorWithInvalidArray() {
        float[] elements = {1, 2, 3, 4, 5};
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            new Matrix4x4(elements);
        }, "Конструктор должен выбрасывать исключение при неверном размере массива");
    }

    // Тестирование конструктора, создающего единичную матрицу
    @Test
    public void testIdentityConstructor() {
        Matrix4x4 identity = new Matrix4x4(1);
        float[][] expected = {
            {1, 0, 0, 0},
            {0, 1, 0, 0},
            {0, 0, 1, 0},
            {0, 0, 0, 1}
        };
        Assertions.assertArrayEquals(expected, identity.getElements(),
            "Конструктор с параметром 1 должен создавать единичную матрицу");
    }

    // Тестирование конструктора по умолчанию (создает нулевую матрицу)
    @Test
    public void testDefaultConstructor() {
        Matrix4x4 zero = new Matrix4x4();
        float[][] expected = {
            {0, 0, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        };
        Assertions.assertArrayEquals(expected, zero.getElements(),
            "Конструктор по умолчанию должен создавать нулевую матрицу");
    }

    // Тестирование метода сложения матриц
    @Test
    public void testAdd() {
        float[] elementsA = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        float[] elementsB = {
            16, 15, 14, 13,
            12, 11, 10, 9,
            8, 7, 6, 5,
            4, 3, 2, 1
        };
        Matrix4x4 A = new Matrix4x4(elementsA);
        Matrix4x4 B = new Matrix4x4(elementsB);
        Matrix4x4 expected = new Matrix4x4(new float[] {
            17, 17, 17, 17,
            17, 17, 17, 17,
            17, 17, 17, 17,
            17, 17, 17, 17
        });
        Matrix4x4 result = A.add(B);
        Assertions.assertEquals(expected, result, "Сложение матриц неверно");
    }

    // Тестирование метода вычитания матриц
    @Test
    public void testSubtract() {
        float[] elementsA = {
            16, 15, 14, 13,
            12, 11, 10, 9,
            8, 7, 6, 5,
            4, 3, 2, 1
        };
        float[] elementsB = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        Matrix4x4 A = new Matrix4x4(elementsA);
        Matrix4x4 B = new Matrix4x4(elementsB);
        Matrix4x4 expected = new Matrix4x4(new float[] {
            15, 13, 11, 9,
            7, 5, 3, 1,
            -1, -3, -5, -7,
            -9, -11, -13, -15
        });
        Matrix4x4 result = A.subtract(B);
        Assertions.assertEquals(expected, result, "Вычитание матриц неверно");
    }

    // Тестирование метода умножения матрицы на вектор
    @Test
    public void testMultiplyWithVector() {
        float[] elements = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        Vector4f vector = new Vector4f(1, 0, -1, 2);
        Vector4f expected = new Vector4f(
            1*1 + 2*0 + 3*(-1) + 4*2,  // 1 + 0 -3 + 8 = 6
            5*1 + 6*0 + 7*(-1) + 8*2,  // 5 + 0 -7 + 16 = 14
            9*1 + 10*0 + 11*(-1) + 12*2, // 9 + 0 -11 +24 = 22
            13*1 + 14*0 + 15*(-1) + 16*2 // 13 +0 -15 +32 = 30
        );
        Vector4f result = matrix.multiply(vector);
        Assertions.assertEquals(expected, result, "Умножение матрицы на вектор неверно");
    }

    // Тестирование умножения матрицы на вектор с инвалидным типом
    @Test
    public void testMultiplyWithInvalidVector() {
        Vector3f invalidVector = new Vector3f(1, 2, 3);
        Matrix4x4 matrix = new Matrix4x4(new float[] {
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        });
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            matrix.multiply(invalidVector);
        }, "Умножение на неверный тип вектора должно выбрасывать исключение");
    }

    // Тестирование метода умножения матриц
    @Test
    public void testMultiplyWithMatrix() {
        float[] elementsA = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        float[] elementsB = {
            16, 15, 14, 13,
            12, 11, 10, 9,
            8, 7, 6, 5,
            4, 3, 2, 1
        };
        Matrix4x4 A = new Matrix4x4(elementsA);
        Matrix4x4 B = new Matrix4x4(elementsB);
        Matrix4x4 expected = new Matrix4x4(new float[] {
            (1*16 + 2*12 + 3*8 + 4*4),
            (1*15 + 2*11 + 3*7 + 4*3),
            (1*14 + 2*10 + 3*6 + 4*2),
            (1*13 + 2*9 + 3*5 + 4*1),

            (5*16 + 6*12 + 7*8 + 8*4),
            (5*15 + 6*11 + 7*7 + 8*3),
            (5*14 + 6*10 + 7*6 + 8*2),
            (5*13 + 6*9 + 7*5 + 8*1),

            (9*16 + 10*12 + 11*8 + 12*4),
            (9*15 + 10*11 + 11*7 + 12*3),
            (9*14 + 10*10 + 11*6 + 12*2),
            (9*13 + 10*9 + 11*5 + 12*1),

            (13*16 + 14*12 + 15*8 + 16*4),
            (13*15 + 14*11 + 15*7 + 16*3),
            (13*14 + 14*10 + 15*6 + 16*2),
            (13*13 + 14*9 + 15*5 + 16*1)
        });
        Matrix4x4 result = A.multiply(B);
        Assertions.assertEquals(expected, result, "Умножение матриц неверно");
    }

    // Тестирование умножения матрицы на матрицу с инвалидным типом
    @Test
    public void testMultiplyWithInvalidMatrix() {
        Matrix3x3 invalidMatrix = new Matrix3x3(new float[] {1, 2, 3, 4, 5, 6, 7, 8, 9});
        Matrix4x4 matrix = new Matrix4x4(new float[] {
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        });
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            matrix.multiply(invalidMatrix);
        }, "Умножение на неверный тип матрицы должно выбрасывать исключение");
    }

    // Тестирование метода транспонирования матрицы
    @Test
    public void testTransposition() {
        float[] elements = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        matrix.transposition();
        Matrix4x4 expected = new Matrix4x4(new float[] {
            1, 5, 9, 13,
            2, 6, 10, 14,
            3, 7, 11, 15,
            4, 8, 12, 16
        });
        Assertions.assertEquals(expected, matrix, "Транспонирование матрицы выполнено неверно");
    }

    // Тестирование метода toString
    @Test
    public void testToString() {
        float[] elements = {
            1.5f, 2.25f, 3.75f, 4.0f,
            5.5f, 6.125f, 7.375f, 8.625f,
            9.875f, 10.5f, 11.25f, 12.75f,
            13.9f, 14.8f, 15.65f, 16.55f
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        String expected = "1,50\t2,25\t3,75\t4,00\t\n" +
                          "5,50\t6,13\t7,38\t8,63\t\n" +
                          "9,88\t10,50\t11,25\t12,75\t\n" +
                          "13,90\t14,80\t15,65\t16,55\t\n";
        Assertions.assertEquals(expected, matrix.toString(), "Метод toString возвращает неверное представление матрицы");
    }

    // Тестирование метода equals и hashCode
    @Test
    public void testEqualsAndHashCode1() {
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });
        Matrix4x4 B = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });
        Matrix4x4 C = new Matrix4x4(new float[] {
            16, 15, 14, 13,
            12, 11, 10, 9,
            8, 7, 6, 5,
            4, 3, 2, 1
        });

        // Проверка равенства
        Assertions.assertEquals(A, B, "Матрицы с одинаковыми элементами должны быть равны");
        Assertions.assertNotEquals(A, C, "Матрицы с разными элементами не должны быть равны");

        // Проверка hashCode
        Assertions.assertEquals(A.hashCode(), B.hashCode(), "Хэш-коды равных матриц должны совпадать");
        Assertions.assertNotEquals(A.hashCode(), C.hashCode(), "Хэш-коды разных матриц не должны совпадать");
    }

    // Тестирование операций с нулевой матрицей
    @Test
    public void testOperationsWithZeroMatrix() {
        Matrix4x4 zero = new Matrix4x4(); // Нулевая матрица
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });

        // Сложение с нулевой матрицей
        Matrix4x4 addResult = A.add(zero);
        Assertions.assertEquals(A, addResult, "Сложение с нулевой матрицей должно возвращать исходную матрицу");

        // Вычитание нулевой матрицы
        Matrix4x4 subtractResult = A.subtract(zero);
        Assertions.assertEquals(A, subtractResult, "Вычитание нулевой матрицы должно возвращать исходную матрицу");

        // Умножение на нулевую матрицу
        Matrix4x4 multiplyResult = A.multiply(zero);
        Matrix4x4 expected = new Matrix4x4(); // Нулевая матрица
        Assertions.assertEquals(expected, multiplyResult, "Умножение на нулевую матрицу должно возвращать нулевую матрицу");
    }

    // Тестирование умножения матрицы на саму себя
    @Test
    public void testMultiplyWithItself1() {
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 0, 1, 3,
            4, 1, 0, 2,
            5, 2, 1, 0,
            3, 0, 2, 1
        });
        Matrix4x4 expected = new Matrix4x4(new float[] {
            (2*2 + 0*4 + 1*5 + 3*3),
            (2*0 + 0*1 + 1*2 + 3*0),
            (2*1 + 0*0 + 1*1 + 3*2),
            (2*3 + 0*2 + 1*0 + 3*1),

            (4*2 + 1*4 + 0*5 + 2*3),
            (4*0 + 1*1 + 0*2 + 2*0),
            (4*1 + 1*0 + 0*1 + 2*2),
            (4*3 + 1*2 + 0*0 + 2*1),

            (5*2 + 2*4 + 1*5 + 0*3),
            (5*0 + 2*1 + 1*2 + 0*0),
            (5*1 + 2*0 + 1*1 + 0*2),
            (5*3 + 2*2 + 1*0 + 0*1),

            (3*2 + 0*4 + 2*5 + 1*3),
            (3*0 + 0*1 + 2*2 + 1*0),
            (3*1 + 0*0 + 2*1 + 1*2),
            (3*3 + 0*2 + 2*0 + 1*1)
        });
        Matrix4x4 result = A.multiply(A);
        Assertions.assertEquals(expected, result, "Умножение матрицы на саму себя выполнено неверно");
    }



    // Тестирование умножения матрицы на единичную матрицу
    @Test
    public void testMultiplyWithIdentityMatrix() {
        Matrix4x4 identity = new Matrix4x4(1);
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 4, 6, 8,
            1, 3, 5, 7,
            0, 2, 4, 6,
            3, 6, 9, 12
        });
        Matrix4x4 result = A.multiply(identity);
        Assertions.assertEquals(A, result, "Умножение матрицы на единичную матрицу должно возвращать исходную матрицу");
    }

    // Тестирование умножения единичной матрицы на матрицу
    @Test
    public void testIdentityMultiplyWithMatrix() {
        Matrix4x4 identity = new Matrix4x4(1);
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 4, 6, 8,
            1, 3, 5, 7,
            0, 2, 4, 6,
            3, 6, 9, 12
        });
        Matrix4x4 result = identity.multiply(A);
        Assertions.assertEquals(A, result, "Умножение единичной матрицы на матрицу должно возвращать исходную матрицу");
    }


    // Тестирование методов сложения и вычитания с нулевой матрицей
    @Test
    public void testAddSubtractWithZeroMatrix() {
        Matrix4x4 zero = new Matrix4x4(); // Нулевая матрица
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });

        // Сложение с нулевой матрицей
        Matrix4x4 addResult = A.add(zero);
        Assertions.assertEquals(A, addResult, "Сложение с нулевой матрицей должно возвращать исходную матрицу");

        // Вычитание нулевой матрицы
        Matrix4x4 subtractResult = A.subtract(zero);
        Assertions.assertEquals(A, subtractResult, "Вычитание нулевой матрицы должно возвращать исходную матрицу");
    }

    // Тестирование умножения матрицы на единичную матрицу с обеих сторон
    @Test
    public void testMultiplyWithIdentityMatrixBothSides() {
        Matrix4x4 identity = new Matrix4x4(1);
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 4, 6, 8,
            1, 3, 5, 7,
            0, 2, 4, 6,
            3, 6, 9, 12
        });

        // Умножение A * Identity
        Matrix4x4 result1 = A.multiply(identity);
        Assertions.assertEquals(A, result1, "Умножение матрицы на единичную матрицу должно возвращать исходную матрицу");

        // Умножение Identity * A
        Matrix4x4 result2 = identity.multiply(A);
        Assertions.assertEquals(A, result2, "Умножение единичной матрицы на матрицу должно возвращать исходную матрицу");
    }

    // Тестирование операций с разными типами матриц
    @Test
    public void testAddWithInvalidMatrix() {
        Matrix3x3 invalidMatrix = new Matrix3x3(new float[] {1,2,3,4,5,6,7,8,9});
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            A.add(invalidMatrix);
        }, "Сложение с неверным типом матрицы должно выбрасывать исключение");
    }

    @Test
    public void testSubtractWithInvalidMatrix() {
        Matrix3x3 invalidMatrix = new Matrix3x3(new float[] {1,2,3,4,5,6,7,8,9});
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            A.subtract(invalidMatrix);
        }, "Вычитание с неверным типом матрицы должно выбрасывать исключение");
    }

    // Тестирование умножения матрицы на нулевую матрицу
    @Test
    public void testMultiplyWithZeroMatrix() {
        Matrix4x4 zero = new Matrix4x4(); // Нулевая матрица
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 4, 6, 8,
            1, 3, 5, 7,
            0, 2, 4, 6,
            3, 6, 9, 12
        });
        Matrix4x4 result = A.multiply(zero);
        Matrix4x4 expected = new Matrix4x4(); // Нулевая матрица
        Assertions.assertEquals(expected, result, "Умножение на нулевую матрицу должно возвращать нулевую матрицу");
    }

    // Тестирование транспонирования транспонированной матрицы (должна вернуть исходную матрицу)
    @Test
    public void testDoubleTransposition() {
        float[] elements = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        matrix.transposition();
        matrix.transposition();
        Matrix4x4 expected = new Matrix4x4(elements);
        Assertions.assertEquals(expected, matrix, "Двойное транспонирование должно вернуть исходную матрицу");
    }



    // Тестирование методов сложения, вычитания и скалярного произведения с нулевой матрицей и нулевым вектором
    @Test
    public void testOperationsWithZeroMatrixAndZeroVector() {
        Matrix4x4 zeroMatrix = new Matrix4x4(); // Нулевая матрица
        Matrix4x4 A = new Matrix4x4(new float[] {
            2, 4, 6, 8,
            1, 3, 5, 7,
            0, 2, 4, 6,
            3, 6, 9, 12
        });

        // Сложение с нулевой матрицей
        Matrix4x4 addResult = A.add(zeroMatrix);
        Assertions.assertEquals(A, addResult, "Сложение с нулевой матрицей должно возвращать исходную матрицу");

        // Вычитание нулевой матрицы
        Matrix4x4 subtractResult = A.subtract(zeroMatrix);
        Assertions.assertEquals(A, subtractResult, "Вычитание нулевой матрицы должно возвращать исходную матрицу");

        // Умножение на нулевую матрицу
        Matrix4x4 multiplyResult = A.multiply(zeroMatrix);
        Matrix4x4 expected = new Matrix4x4(); // Нулевая матрица
        Assertions.assertEquals(expected, multiplyResult, "Умножение на нулевую матрицу должно возвращать нулевую матрицу");
    }

    // Тестирование метода toString с нулевой матрицей
    @Test
    public void testToStringWithZeroMatrix() {
        Matrix4x4 zeroMatrix = new Matrix4x4(); // Нулевая матрица
        String expected = "0,00\t0,00\t0,00\t0,00\t\n" +
                          "0,00\t0,00\t0,00\t0,00\t\n" +
                          "0,00\t0,00\t0,00\t0,00\t\n" +
                          "0,00\t0,00\t0,00\t0,00\t\n";
        Assertions.assertEquals(expected, zeroMatrix.toString(),
            "Метод toString для нулевой матрицы должен возвращать матрицу из нулей");
    }

    // Тестирование операций с разными типами векторов и матриц
    @Test
    public void testMultiplyWithDifferentVectorTypes() {
        Vector3f invalidVector = new Vector3f(1, 2, 3);
        Matrix4x4 matrix = new Matrix4x4(new float[] {
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        });
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            matrix.multiply(invalidVector);
        }, "Умножение на неверный тип вектора должно выбрасывать исключение");
    }

    @Test
    public void testAddAndSubtractWithDifferentMatrixTypes() {
        Matrix3x3 invalidMatrix = new Matrix3x3(new float[] {1,2,3,4,5,6,7,8,9});
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });

        // Добавление с неверным типом матрицы
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            A.add(invalidMatrix);
        }, "Сложение с неверным типом матрицы должно выбрасывать исключение");

        // Вычитание с неверным типом матрицы
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            A.subtract(invalidMatrix);
        }, "Вычитание с неверным типом матрицы должно выбрасывать исключение");
    }

    // Тестирование скалярного произведения
    @Test
    public void testDotProduct() {
        Vector4f v1 = new Vector4f(1.0f, 3.0f, -5.0f, 2.0f);
        Vector4f v2 = new Vector4f(4.0f, -2.0f, -1.0f, 3.0f);
        float expectedDot = 1*4 + 3*(-2) + (-5)*(-1) + 2*3; // 4 -6 +5 +6 = 9
        float resultDot = v1.dot(v2);
        Assertions.assertEquals(9.0f, resultDot, 1e-6, "Скалярное произведение неверно");
    }

    // Тестирование метода equals и hashCode для матриц с разными данными
    @Test
    public void testPartialEquals() {
        Matrix4x4 A = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        });
        Matrix4x4 B = new Matrix4x4(new float[] {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 17 // 1н измененный элемент
        });
        Assertions.assertNotEquals(A, B, "Матрицы с хотя бы одним отличающимся элементом не должны быть равны");
    }
    @Test
    void determinant1() {
        Matrix4x4 identity = new Matrix4x4(1);
        float det = identity.determinant();
        Assertions.assertEquals(1.0f, det, "Определитель единичной матрицы должен быть равен 1");
    }

    @Test
    void determinant2() {
        Matrix4x4 zeroMatrix = new Matrix4x4();
        float det = zeroMatrix.determinant();
        Assertions.assertEquals(0.0f, det, "Определитель нулевой матрицы должен быть равен 0");
    }

    @Test
    void determinant3() {
        float[] elements = {
            5, -2, 2, 7,
            1, 0, 0, 3,
            -3, 1, 5, 0,
            3, -1, -9, 4
        };
        Matrix4x4 matrix = new Matrix4x4(elements);
        float det = matrix.determinant();
        Assertions.assertEquals(88.0f, det, 1e-5, "Определитель матрицы должен быть равен 88");
    }

    @Test
    void determinant4() {
        float[] elements = {
            1, 2, 3, 4,
            2, 4, 6, 8,
            3, 6, 9, 12,
            4, 8, 12, 16
        };
        Matrix4x4 singularMatrix = new Matrix4x4(elements);
        float det = singularMatrix.determinant();
        Assertions.assertEquals(0.0f, det, 1e-5, "Определитель вырожденной матрицы должен быть равен 0");
    }

    @Test
    void determinant5() {
        float[] elements = {
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16
        };
        // матрица вырождена
        Matrix4x4 matrix = new Matrix4x4(elements);
        float det = matrix.determinant();
        Assertions.assertEquals(0.0f, det, 1e-5, "Определитель матрицы должен быть равен 0");
    }


}