#!/usr/bin/ruby

#
## https://rosettacode.org/wiki/Gauss-Jordan_matrix_inversion
#

func rref (M) {
    var (j, rows, cols) = (0, M.len, M[0].len)

    for r in (^rows) {
        j < cols || return M

        var i = r
        while (!M[i][j]) {
            ++i == rows || next
            i = r
            ++j == cols && return M
        }

        M[i, r] = M[r, i] if (r != i)
        M[r] = (M[r] »/» M[r][j])

        for n in (^rows) {
            next if (n == r)
            M[n] = (M[n] »-« (M[r] »*» M[n][j]))
        }
        ++j
    }

    return M
}

func gauss_jordan_invert (M) {

    var I = M.len.of {|i|
        M.len.of {|j|
            i == j ? 1 : 0
        }
    }

    var A = gather {
        ^M -> each {|i| take(M[i] + I[i]) }
    }

    rref(A).map { .last(M.len) }
}

var n = irand(3, 7)

var A = n.of {
    n.of { irand(-10, 10) }
}

say gauss_jordan_invert(A).map {
    .map { "%6s" % .as_rat }.join("  ")
}.join("\n")

assert_eq(A.inv, gauss_jordan_invert(A))
