manpagez: man pages & more
info ginac
Home | html | info | man
[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13 Matrices

A matrix is a two-dimensional array of expressions. The elements of a matrix with m rows and n columns are accessed with two unsigned indices, the first one in the range 0…m-1, the second one in the range 0…n-1.

There are a couple of ways to construct matrices, with or without preset elements. The constructor

 
matrix::matrix(unsigned r, unsigned c);

creates a matrix with ‘r’ rows and ‘c’ columns with all elements set to zero.

The fastest way to create a matrix with preinitialized elements is to assign a list of comma-separated expressions to an empty matrix (see below for an example). But you can also specify the elements as a (flat) list with

 
matrix::matrix(unsigned r, unsigned c, const lst & l);

The function

 
ex lst_to_matrix(const lst & l);

constructs a matrix from a list of lists, each list representing a matrix row.

There is also a set of functions for creating some special types of matrices:

 
ex diag_matrix(const lst & l);
ex unit_matrix(unsigned x);
ex unit_matrix(unsigned r, unsigned c);
ex symbolic_matrix(unsigned r, unsigned c, const string & base_name);
ex symbolic_matrix(unsigned r, unsigned c, const string & base_name,
                   const string & tex_base_name);

diag_matrix() constructs a diagonal matrix given the list of diagonal elements. unit_matrix() creates an ‘x’ by ‘x’ (or ‘r’ by ‘c’) unit matrix. And finally, symbolic_matrix constructs a matrix filled with newly generated symbols made of the specified base name and the position of each element in the matrix.

Matrices often arise by omitting elements of another matrix. For instance, the submatrix S of a matrix M takes a rectangular block from M. The reduced matrix R is defined by removing one row and one column from a matrix M. (The determinant of a reduced matrix is called a Minor of M and can be used for computing the inverse using Cramer's rule.)

 
ex sub_matrix(const matrix&m, unsigned r, unsigned nr, unsigned c, unsigned nc);
ex reduced_matrix(const matrix& m, unsigned r, unsigned c);

The function sub_matrix() takes a row offset r and a column offset c and takes a block of nr rows and nc columns. The function reduced_matrix() has two integer arguments that specify which row and column to remove:

 
{
    matrix m(3,3);
    m = 11, 12, 13,
        21, 22, 23,
        31, 32, 33;
    cout << reduced_matrix(m, 1, 1) << endl;
    // -> [[11,13],[31,33]]
    cout << sub_matrix(m, 1, 2, 1, 2) << endl;
    // -> [[22,23],[32,33]]
}

Matrix elements can be accessed and set using the parenthesis (function call) operator:

 
const ex & matrix::operator()(unsigned r, unsigned c) const;
ex & matrix::operator()(unsigned r, unsigned c);

It is also possible to access the matrix elements in a linear fashion with the op() method. But C++-style subscripting with square brackets ‘[]’ is not available.

Here are a couple of examples for constructing matrices:

 
{
    symbol a("a"), b("b");

    matrix M(2, 2);
    M = a, 0,
        0, b;
    cout << M << endl;
     // -> [[a,0],[0,b]]

    matrix M2(2, 2);
    M2(0, 0) = a;
    M2(1, 1) = b;
    cout << M2 << endl;
     // -> [[a,0],[0,b]]

    cout << matrix(2, 2, lst(a, 0, 0, b)) << endl;
     // -> [[a,0],[0,b]]

    cout << lst_to_matrix(lst(lst(a, 0), lst(0, b))) << endl;
     // -> [[a,0],[0,b]]

    cout << diag_matrix(lst(a, b)) << endl;
     // -> [[a,0],[0,b]]

    cout << unit_matrix(3) << endl;
     // -> [[1,0,0],[0,1,0],[0,0,1]]

    cout << symbolic_matrix(2, 3, "x") << endl;
     // -> [[x00,x01,x02],[x10,x11,x12]]
}

The method matrix::is_zero_matrix() returns true only if all entries of the matrix are zeros. There is also method ex::is_zero_matrix() which returns true only if the expression is zero or a zero matrix.

There are three ways to do arithmetic with matrices. The first (and most direct one) is to use the methods provided by the matrix class:

 
matrix matrix::add(const matrix & other) const;
matrix matrix::sub(const matrix & other) const;
matrix matrix::mul(const matrix & other) const;
matrix matrix::mul_scalar(const ex & other) const;
matrix matrix::pow(const ex & expn) const;
matrix matrix::transpose() const;

All of these methods return the result as a new matrix object. Here is an example that calculates A*B-2*C for three matrices A, B and C:

 
{
    matrix A(2, 2), B(2, 2), C(2, 2);
    A =  1, 2,
         3, 4;
    B = -1, 0,
         2, 1;
    C =  8, 4,
         2, 1;

    matrix result = A.mul(B).sub(C.mul_scalar(2));
    cout << result << endl;
     // -> [[-13,-6],[1,2]]
    ...
}

The second (and probably the most natural) way is to construct an expression containing matrices with the usual arithmetic operators and pow(). For efficiency reasons, expressions with sums, products and powers of matrices are not automatically evaluated in GiNaC. You have to call the method

 
ex ex::evalm() const;

to obtain the result:

 
{
    ...
    ex e = A*B - 2*C;
    cout << e << endl;
     // -> [[1,2],[3,4]]*[[-1,0],[2,1]]-2*[[8,4],[2,1]]
    cout << e.evalm() << endl;
     // -> [[-13,-6],[1,2]]
    ...
}

The non-commutativity of the product A*B in this example is automatically recognized by GiNaC. There is no need to use a special operator here. See section Non-commutative objects, for more information about dealing with non-commutative expressions.

Finally, you can work with indexed matrices and call simplify_indexed() to perform the arithmetic:

 
{
    ...
    idx i(symbol("i"), 2), j(symbol("j"), 2), k(symbol("k"), 2);
    e = indexed(A, i, k) * indexed(B, k, j) - 2 * indexed(C, i, j);
    cout << e << endl;
     // -> -2*[[8,4],[2,1]].i.j+[[-1,0],[2,1]].k.j*[[1,2],[3,4]].i.k
    cout << e.simplify_indexed() << endl;
     // -> [[-13,-6],[1,2]].i.j
}

Using indices is most useful when working with rectangular matrices and one-dimensional vectors because you don't have to worry about having to transpose matrices before multiplying them. See section Indexed objects, for more information about using matrices with indices, and about indices in general.

The matrix class provides a couple of additional methods for computing determinants, traces, characteristic polynomials and ranks:

 
ex matrix::determinant(unsigned algo=determinant_algo::automatic) const;
ex matrix::trace() const;
ex matrix::charpoly(const ex & lambda) const;
unsigned matrix::rank() const;

The ‘algo’ argument of determinant() allows to select between different algorithms for calculating the determinant. The asymptotic speed (as parametrized by the matrix size) can greatly differ between those algorithms, depending on the nature of the matrix' entries. The possible values are defined in the ‘flags.h’ header file. By default, GiNaC uses a heuristic to automatically select an algorithm that is likely (but not guaranteed) to give the result most quickly.

Matrices may also be inverted using the ex matrix::inverse() method and linear systems may be solved with:

 
matrix matrix::solve(const matrix & vars, const matrix & rhs,
                     unsigned algo=solve_algo::automatic) const;

Assuming the matrix object this method is applied on is an m times n matrix, then vars must be a n times p matrix of symbolic indeterminates and rhs a m times p matrix. The returned matrix then has dimension n times p and in the case of an underdetermined system will still contain some of the indeterminates from vars. If the system is overdetermined, an exception is thrown.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]
© manpagez.com 2000-2024
Individual documents may contain additional copyright information.