import { assert } from "../../assert.js";

/**
 * Assumes the system is factorized already. Use {@link lu_factor_linear_system} before if it isn't
 * Solve linear equations Ax = b using LU decomposition A = LU where L is lower triangular matrix and U is upper triangular matrix.
 * Input is factored matrix A=LU, integer array of pivot indices index[0->n-1], load vector x[0->n-1], and size of square matrix n.
 * Note that A=LU and index[] are generated from method LUFactorLinearSystem.
 * Also, solution vector is written directly over input load vector.
 *
 * @param {number[]} A Square matrix, column-major flat layout (pre-factored LU as produced by lu_factor_linear_system)
 * @param {number[]|Uint32Array} index
 * @param {number[]} x Load vector
 * @param {number} size matrix size ( 4x4 matrix has size 4)
 */
export function lu_solve_linear_system(A, index, x, size) {
    assert.isNonNegativeInteger(size, 'size');

    let i = 0, j, ii = -1;

    let sum;

    // Proceed with forward and back-substitution for L and U matrices.

    // First, forward substitution.
    for (; i < size; ++i) {
        const idx = index[i];
        sum = x[idx];
        x[idx] = x[i];

        if (ii >= 0) {

            for (j = ii; j <= i - 1; ++j) {
                sum -= A[j * size + i] * x[j];
            }

        } else if (sum !== 0.0) {
            ii = i;
        }

        x[i] = sum;
    }

    // Now, back substitution
    for (i = size - 1; i >= 0; i--) {
        sum = x[i];

        for (j = i + 1; j < size; ++j) {
            sum -= A[j * size + i] * x[j];
        }

        x[i] = sum / A[i * size + i];
    }
}
