libgfx: Matrix Math
Author: Michael Garland

## Matrix Math

The `libgfx` matrix math package is the companion to the vector package and are intended to provide a convenient way of writing vector/matrix equations. Currently, only square matrices of dimension 2x2 [`Mat2`], 3x3 [`Mat3`], and 4x4 [`Mat4`].

A matrix consists of n*n double precision floating point values. Unlike the vector package, the matrix package is not yet template-based. Matrix elements are accessed using 0-indexed (row, column) pairs. Thus, a 2x2 identity matrix can be constructed as follows:

        Mat2 A;

        A(0, 0) = 1.0;
        A(0, 1) = 0.0;
        A(1, 0) = 0.0;
        A(1, 1) = 1.0;

The default constructors (as used above) initialize all elements to 0. All matrix classes also provide constructors which accept a list of row vectors to initialize their elements. Thus, the following example is equivalent to the code above:

        Mat2 A(Vec2(1.0, 0.0), Vec2(1.0, 0.0));

Matrices can also be automatically case to `double` pointers. Since matrices are stored in row-major order, the follow code would change element (0, 1) of the matrix above:

        double *B = A;
        B[1] = -1.0;

Warning: For efficiency reasons, accessors are not range checked. Thus you can legally write

        Mat2 v;
        v(-10, 37) = 1.0;

and generate an invalid memory access.

### Arithmetic Operators

Like the vector package, one of the primary goals of the matrix package is to simplify the writing of vector/matrix equations. To accomplish this, it makes use of C++ operator overloading.

Assignment Matrices can be assigned the values of other matrices or scalars. A matrix assignment `A = B` copies the elements of `B` into the corresponding elements of `A`. A scalar assignment `A = 1.0` copies the given scalar, in this case `1.0`, into each of the elements of `A`.

Addition/Subtraction Matrices can be added together either with the binary addition operator (`C = A + B`) or the additive assignment operator (`A += B`). Subtraction operates similarly, using subtraction rather than addition operators.

Scalar Multiplication/Division Matrices can be multiplied by scalar values using either the binary operator (`A * 2.0`) or the accumulation operator (`A *= 2.0`). Scalar division operates similarly.

Matrix/Vector Multiplication Matrices can be multiplied together with a binary operator (`A * B`). Matrices can also multiply vectors (`A * v`) which returns a new vector.

### Standard Matrix Functions

All matrix classes support a standard set of functions for performing common operations on matrices. The functions are:

    // Constructs the outer product of the two vectors
    Mat_ outer_product(const Vec_ &u, const Vec_ &v);

    // Returns the determinant of the matrix
    double det(const Mat_ &A);

    // Returns the trace of the matrix (the sum of the diagonals)
    double trace(const Mat_ &A);

    // Returns the transpose of A
    Mat_ transpose(const Mat_ &A);

    // Returns the adjoint of A
    Mat_ adjoint(const Mat_ &A);

    // Places the inverse of A in A_inv and returns det(A)
    // The contents of A_inv are undefined if the inverse doesn't exist.
    double invert(Mat_ &A_inv, const Mat_ &A);

Matrices can also be read from and written to C++ iostreams using the standard `<<` and `>>` operators.