English  Español  Português  Français  Italiano  Deutsch  Nederlands  Svenska  Dansk  Suomi  Norsk  Русский  Polski  Română  Български  Hrvatski  Česky  中国  中國  日本語  한국어  Ελληνική  हिन्दी  العربية 
Linear Algebra
Colin Fahey

1. Ohjelmisto

LinearAlgebra.zip
Linear algebra lähdekoodi (C#)
19910 bytes
MD5: 11d8c8035cac30ba543e5e0b72ee9767

2. Johdanto

Tässä artikkelissa kuvataan vektoreiden ja matriisien vuonna (d)-ulotteinen avaruus.

3. (d)-ulotteinen avaruus: Määritteet

3.1 Array

"array:" A kokoelma muuttujia siten, että kukin muuttuja on ainutlaatuinen nimi, ja sellainen, että nimiä voidaan antaa tilauksen.
Integer-arvoja voidaan käyttää nimiä muuttujat jono.
Esimerkiksi, jos jono sisältää (d) muuttujat, sitten kokonaislukuarvoista { 0, 1, 2, ..., (d-1) } voidaan nimet annetaan muuttujat, että jono.

3.2 (d)-ulotteinen vektori

"(d)-ulotteinen vektori:" runsaasti (d) muuttujia.
"vektorin komponentti:" A muuttuja, joka vektoria.

3.3 (d)-ulotteinen vektori avaruus

"yksi yhtenäinen tila:" kattava joukko arvoja, jotka voidaan tallentaa yksi muuttuja.
"(d)-ulotteinen avaruus:" Täydellinen sarja yhdistelmiä arvoista, joita voidaan varastoida, jonka joukko (d) muuttujia.
Muodollinen määritelmä on "vektori avaruus:"
Let (T) olla perus tyyppi (esimerkkejä: reaaliluku, kokonaisluku, Kompleksiluku, Rationaaliluku jne.).
Kaikki muuttujan perustason tyyppi on nimetty yksi "scalar."
A "(T)-tyypin (d)-ulotteinen vektori avaruus" on asetettu (S), (d)-ulotteisten vektorien ottaa kaksi operaatiota, vektori lisäksi (+), ja scalar multiplication (*), täytä alla:
(1) Jos (v) ja (w) ovat minkä tahansa kahden vektorit, (S), sitten (v + w) on myös vektorin (S);
(2) Jos (u), (v), ja (w) ovat kolmen vektorit, (S), sitten (u + v) + w = u + (v + w);
[lisäaineen commutativity]
(3) Jos (v) ja (w) ovat minkä tahansa kahden vektorit, (S), sitten (v + w) = (w + v);
[lisäaineen associativity]
(4) on "nolla vektori," (0), (S) siten, että kaikki vektorin (v) vuonna (S), (v + (0)) = v;
[lisäaineen identiteetin]
(5) Jos (c) on mikä tahansa scalar tyypin (T), ja (v) on mikä tahansa vektorin (S), sitten tuote (c * v) on vektorin (S);
(6) Jos (a), (b), ja (c) ovat kaikki scalars tyypin (T), ja (v) ja (w) ovat kaikki vektorit, (S), sitten (a + b) * v = a*v + b*v, ja c*(v + w) = c*v + c*w;
[multiplicative distributivity]
(7) Jos (a) ja (b) ovat kaikki scalars tyypin (T), ja (v) on mikä tahansa vektorin (S), sitten (a*b)*v = a*(b*v);
(8) Jos "1" on scalar tyypin (T) sellainen, että (1*1)=1, ja (v) on mikä tahansa vektorin (S), sitten (1*v) = v;
(9) Kunkin vektorin (v) vuonna (S), vektori (-1)*v = -v täyttää v + (-v) = (0);
[vastaluku]

3.4 (d)-ulotteinen vektori-koodi

Alla oleva koodi osoittaa, kuinka (d)-ulotteinen vektori, joissa on 64-bittinen kelluvia-kohta komponentteja, voidaan panna täytäntöön.
Jono on riittävän edustavat vektoria.
Alla oleva koodi on jono sisältyvät luokkaan, vain mukavuussyistä.
Koodi ei ole tarkoitus olla tehokasta.
A rakennetta (esimerkki: "struct", arvon tyyppi) edustavat vektoreilla kiinteä määrä mitat (esimerkkejä: 3 tai 4) on todennäköisesti paljon tehokkaampi kuin yleinen (d)-ulotteinen vektori-luokan esitetään tässä.
Vaikka alla oleva koodi määritellään vektori kanssa kelluvia-kohta komponentteja, tässä asiakirjassa myös käyttää vektorien kanssa integer komponentteja.
Alla oleva koodi voidaan helposti muutettu toteuttaa vektorien kanssa integer komponentteja.
using System;
using System.Collections.Generic;
using System.Text;

// Multidimensional vector with 64-bit floating-point components:

public class VectorF64
{
    private double[] components;




    public int Dimensions()
    {
        if (null == this.components)
        {
            return (0);
        }

        return (this.components.Length);
    }




    public VectorF64()
    {
        this.components = null;
    }




    public VectorF64params double[] paramValues )
    {
        this.components = null;

        if (null == paramValues)
        {
            return;
        }

        int dimensions = paramValues.Length;

        this.components = new double[dimensions];

        for (int i = 0; i < dimensions; i++)
        {
            this.components[i] = paramValues[i];
        }
    }




    public VectorF64VectorF64 other )
    {
        this.components = null;

        if (null == other)
        {
            return;
        }

        if (null == other.components)
        {
            return;
        }

        int dimensions = other.Dimensions();

        this.components = new double[dimensions];

        for (int i = 0; i < dimensions; i++)
        {
            this.components[i] = other.components[i];
        }
    }




    public double this[int index]
    {
        get
        {
            if (null == this.components)
            {
                return (0.0);
            }

            if
            (
                   (index >= 0)
                && (index < this.components.Length)
            )
            {
                return (this.components[index]);
            }

            return (0.0);
        }

        set
        {
            if (null == this.components)
            {
                return;
            }

            if
            (
                   (index >= 0)
                && (index < this.components.Length)
            )
            {
                this.components[index] = value;
            }
        }
    }




    public void Write( int precision )
    {
        if (null == this.components)
        {
            Log.Write( String.Empty + '(' + ' ' + ')' );
            return;
        }

        int dimensions = this.Dimensions();
        if (0 == dimensions)
        {
            Log.Write( String.Empty + '(' + ' ' + ')' );
            return;
        }

        // Determine the largest component width in characters
        // so that we can make all components an equal width.
        int largestComponentWidth = 1;
        for (int i = 0; i < dimensions; i++)
        {
            // { index [,minwidth] [:typeCode[precision]] }
            //      (minwidth<0) means left-justify
            String text = String.Format( String.Empty + '{' + '0' + ':'
                + 'g' + precision + '}', this[i] );
            if (text.Length > largestComponentWidth)
            {
                largestComponentWidth = text.Length;
            }
        }

        Log.Write( '(' );
        for (int i = 0; i < dimensions; i++)
        {
            Log.Write( ' ' );
            String text =
                String.Format( String.Empty + '{' + '0' + ','
                + largestComponentWidth + ':' + 'g' + precision + '}',
                this[i] );
            Log.Write( text );
            if ((i + 1) < dimensions)
            {
                Log.Write( ',' );
            }
            else
            {
                Log.Write( ' ' );
            }
        }
        Log.Write( ')' );
    }




    public void WriteLine( int precision )
    {
        this.Write( precision );
        Log.WriteLine();
    }




    public void WriteLine()
    {
        const int defaultPrecision = 8;
        this.Write( defaultPrecision );
        Log.WriteLine();
    }




    // . . .




    public static void Test()
    {
        // A 3-dimensional vector with 64-bit floating-point components:
        VectorF64 v3 = new VectorF640.01.02.0 );
        v3.WriteLine(); // ( 0, 1, 2 )

        // A 4-dimensional vector with 64-bit floating-point components:
        VectorF64 v4 = new VectorF640.01.02.03.0 );
        v4.WriteLine(); // ( 0, 1, 2, 3 )

        // . . .
    }
}
"(d)-ulotteinen nolla vektori:" A vektorin kaikki (d) komponenttien nolla.
public class VectorF64
{
    // . . .




    public static VectorF64 Zero( int dimensions )
    {
        VectorF64 zero = new VectorF64();

        zero.components = new double[dimensions];

        for (int i = 0; i < dimensions; i++)
        {
            zero[i] = 0.0;
        }

        return (zero);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // An 8-dimensional vector with all 8 64-bit floating-point
        // components set to zero:
        VectorF64 z = VectorF64.Zero( 8 );
        z.WriteLine(); // ( 0, 0, 0, 0, 0, 0, 0, 0 )


        // . . .
    }
}

3.5 (d)-ulotteinen avaruus: kohdat

"(d)-ulotteinen avaruus kohta:" runsaasti (d) muuttujien arvoja "(koordinoimaan-arvot)."
"(d)-ulotteinen avaruus Kotipaikka:" An array, (d) muuttujien kaikki arvot nolla.

3.6 (d)-ulotteisten vektorien: ei-suhteellinen ja suhteellinen

A (d)-ulotteinen vektori, joka on "ei-suhteellinen" on (d)-ulotteinen vektori, että suoraan edustaa tilan tai kokoonpano.
A (d)-ulotteinen vektori, joka on "suhteellinen" on (d)-ulotteinen vektori, joka edustaa muutoksia joukko komponentteja.
Suhteellinen vektori voi edustaa ero kahden ei-suhteellinen vektorit.
Koska suhteellinen vektori, määritettäessä ei-suhteellinen asema tai kokoonpano käyttäen, että suhteellinen vektori edellyttää yhdistämällä, että suhteellinen vektori ilman suhteellinen vektori.
Ei-suhteellinen vektoreiden ja suhteellinen vektorit ovat molemmat vektorit.
Onko tietty vektori ei ole suhteellista tai suhteessa on täsmennettävä, jos vektori on määritelty.
Jos (d)-ulotteinen vektori on tulkittava siten, että ei-suhteellinen, sitten (d)-ulotteinen vektori voi edustaa piste (d)-ulotteinen avaruus.

3.7 (d)-ulotteinen vektori lisäksi, subtraction, ja skaalaus

Vector lisäksi, subtraction, ja skaalaus:
public class VectorF64
{
    // . . .




    public static VectorF64 operator +( VectorF64 a, VectorF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (new VectorF64()); // Vector not specified.
        }

        if ((null == a.components) || (null == b.components))
        {
            return (new VectorF64()); // Vector is empty.
        }

        if (a.Dimensions() != b.Dimensions())
        {
            return (new VectorF64()); // Vectors not the same size.
        }

        int dimensions = a.Dimensions();

        VectorF64 result = VectorF64.Zero( dimensions );

        for (int i = 0; i < dimensions; i++)
        {
            result[i] = a[i] + b[i];
        }

        return (result);
    }




    public static VectorF64 operator -( VectorF64 a, VectorF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (new VectorF64()); // Vector not specified.
        }

        if ((null == a.components) || (null == b.components))
        {
            return (new VectorF64()); // Vector is empty.
        }

        if (a.Dimensions() != b.Dimensions())
        {
            return (new VectorF64()); // Vectors not the same size.
        }

        int dimensions = a.Dimensions();

        VectorF64 result = VectorF64.Zero( dimensions );

        for (int i = 0; i < dimensions; i++)
        {
            result[i] = a[i] - b[i];
        }

        return (result);
    }




    public static VectorF64 operator -( VectorF64 a )
    {
        if (null == a)
        {
            return (new VectorF64()); // Vector not specified.
        }

        if (null == a.components)
        {
            return (new VectorF64()); // Vector is empty.
        }

        int dimensions = a.Dimensions();

        VectorF64 result = VectorF64.Zero( dimensions );

        for (int i = 0; i < dimensions; i++)
        {
            result[i] = (-( a[i] ));
        }

        return (result);
    }




    public static VectorF64 operator *( double scale, VectorF64 a )
    {
        if (null == a)
        {
            return (new VectorF64()); // Vector not specified.
        }

        if (null == a.components)
        {
            return (new VectorF64()); // Vector is empty.
        }

        int dimensions = a.Dimensions();

        VectorF64 result = VectorF64.Zero( dimensions );

        for (int i = 0; i < dimensions; i++)
        {
            result[i] = scale * a[i];
        }

        return (result);
    }




    public static VectorF64 operator *( VectorF64 a, double scale )
    {
        if (null == a)
        {
            return (new VectorF64()); // Vector not specified.
        }

        if (null == a.components)
        {
            return (new VectorF64()); // Vector is empty.
        }

        int dimensions = a.Dimensions();

        VectorF64 result = VectorF64.Zero( dimensions );

        for (int i = 0; i < dimensions; i++)
        {
            result[i] = scale * a[i];
        }

        return (result);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Examples of vector addition, subtraction, and scaling:

        VectorF64 a = new VectorF640.01.02.03.0 );
        a.WriteLine(); // ( 0, 1, 2, 3 )
        VectorF64 b = new VectorF643.02.01.00.0 );
        b.WriteLine(); // ( 3, 2, 1, 0 )
        VectorF64 c = new VectorF64();
        c.WriteLine(); // ( )

        c = a + b;
        c.WriteLine(); // ( 3, 3, 3, 3 )

        c = a - b;
        c.WriteLine(); // ( -3, -1,  1,  3 )

        c = -b;
        c.WriteLine(); // ( -3, -2, -1,  0 )

        c = 3.0 * a;
        c.WriteLine(); // ( 0, 3, 6, 9 )


        // . . .
    }
}

3.8 (d)-ulotteinen perusteella vektorit

Muodollinen määritelmä, jonka "pohjana" on vektori avaruus:
Let (T) olla perus tyyppi (esimerkkejä: reaaliluku, kokonaisluku, Kompleksiluku, Rationaaliluku jne.).
Kaikki muuttujan perustason tyyppi on nimetty yksi "scalar."
Let (V) olla "(T)-tyypin (d)-ulotteinen vektori tilaa."
Jos muu kuin nolla vektorit { u1, u2, ..., ud } vuonna (V) ovat sellaiset, että jokainen vektori (v) vuonna (V) voi olla kirjallinen kuten "lineaarinen yhdistelmä" nämä vektorit, v = c1*u1 + c2*u2 + ...  + cd*ud, jossa { c1, c2, ..., cd } ovat scalars tyypin (T), sitten (V) on "jakautuivat" jonka vektorit { u1, u2, ..., ud }.
Mitään ei-nolla, vektorit { u1, u2, ..., ud } että "span" Vektoriavaruus (V) on nimetty "pohjalta" (V).
Yksi yksinkertainen "perusteella," (d)-ulotteinen vektori avaruus on joukko (d) erilliset (d)-ulotteisten vektorien, joilla kullakin on yksi osa yhtä ja kaikki muut osat nolla.
Tällainen perusteella vektorit ovat "orthonormal," mikä tarkoittaa, että ne ovat toisiaan kohtisuorassa "(osittainen)" ja että jokainen vektori on yksikön pituus.
Jokainen tällainen vektori on yksikkö vektorin rinnalla yhtenä (d) koordinoida akseleilla.
Ilmaisivat mielivaltainen vektori on "lineaarinen" näiden "yhdistelmä" perusteella vektorit on välitön; kunkin osan mielivaltainen vektori on kerrottuna vastaavalla perusteella vektori, ja näitä tuotteita lisätään yhdessä muodostavat mielivaltainen vektori.
Alla oleva koodi osoittaa, kuinka vektori voidaan ilmaista "lineaarinen yhdistelmä" perusteella vektorit.
Alla oleva koodi mielivaltaisesti määritellään orthonormal joukon perusteella vektorit.
public class VectorF64
{
    // . . .




    public static VectorF64 BasisVector( int dimensions, int componentIndex )
    {
        if (dimensions < 0)
        {
            // Invalid number of dimensions specified.
            return (new VectorF64());
        }

        VectorF64 basisVector = VectorF64.Zero( dimensions );

        if ((componentIndex >= 0) && (componentIndex < dimensions))
        {
            basisVector[ componentIndex ] = 1.0;
        }

        return (basisVector);
    }




    // . . .




    public static void Test()
    {

        // . . .


        // The 4 basis vectors of 4-dimensional space,
        // each with 4 64-bit floating-point components:

        VectorF64 b0 = VectorF64.BasisVector( 40 );
        b0.WriteLine(); // ( 1, 0, 0, 0 )

        VectorF64 b1 = VectorF64.BasisVector( 41 );
        b1.WriteLine(); // ( 0, 1, 0, 0 )

        VectorF64 b2 = VectorF64.BasisVector( 42 );
        b2.WriteLine(); // ( 0, 0, 1, 0 )

        VectorF64 b3 = VectorF64.BasisVector( 43 );
        b3.WriteLine(); // ( 0, 0, 0, 1 )


        // . . .
    }
}
Kaikki vektorin (d)-ulotteinen avaruus voidaan ilmaista summa tuotteiden numerot ja perusta vektorit:
public class VectorF64
{
    // . . .




    public static void Test()
    {

        // . . .


        // The following two vectors are equivalent:

        // A 4-dimensional vector with 64-bit floating-point components:
        VectorF64 va = new VectorF640.11.12.23.3 );
        va.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )

        // A 4-dimensional vector formed by scaling the 4 independent
        // basis vectors for 4-dimensional space:
        VectorF64 vb =
              0.1 * VectorF64.BasisVector( 40 )
            + 1.1 * VectorF64.BasisVector( 41 )
            + 2.2 * VectorF64.BasisVector( 42 )
            + 3.3 * VectorF64.BasisVector( 43 );
        vb.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )


        // . . .
    }
}

3.9 (d)-ulotteinen avaruus: välimatka pistettä

Let (P) olla (d)-ulotteinen vektori, joka edustaa piste (d)-ulotteinen avaruus.
Let (Q) olla (d)-ulotteinen vektori, joka edustaa piste (d)-ulotteinen avaruus.
Let (R) olla (d)-ulotteinen vektori, joka edustaa muutosta (d) koordinaatit saada piste (P) kohtaan (Q); R = (Q - P).
Yhdessä-ulotteinen avaruus, P = ( p0 ), Q = ( q0 ), ja R = (Q - P) = ( q0 - p0 ).
Sen etäisyys kahden pisteen välillä on: Abs( q0 - p0 ).
Vuonna kaksiulotteinen avaruus, P = ( p0, p1 ), Q = ( q0, q1 ), ja R = (Q - P) = ( q0-p0, q1-p1 ).
Tulkkaus kahden kohtisuorassa siirtymien kuin kohtisuorassa puolin oikeus-kolmiota, välinen etäisyys pistettä vastaa pituus, hypotenuse kyseisen kolmion.
The Pythagorean kaava, (a*a) + (b*b) = (c*c), jossa (a) ja (b) ovat pituudet on kohtisuorassa puolin oikeus-kolmiota, ja (c) pitkä on hypotenuse (skew puolelta), voidaan määrittää etäisyys kahden pisteen välillä: Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
Vuonna kolmiulotteisuus, P = ( p0, p1, p2 ), Q = ( q0, q1, q2 ), ja R = (Q - P) = ( q0-p0, q1-p1, q2-p2 ).
Tulkkaus on joutunut jättämään kotinsa ( q0-p0, q1-p1, 0 ) kuin kohtisuorassa puolin oikeus-kolmiota, ja käyttämällä Pythagorean kaava, on antanut välinen etäisyys kohta (P) ja kohta ( q0, q1, p2 ): d01 = Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
The displacement ( q0-p0, q1-p1, 0 ) on kohtisuorassa joutui jättämään ( 0, 0, q2-p2 ), ja toinen oikeus-kolmio voidaan muodostaa, ja Pythagorean kaavaa voidaan käyttää uudelleen.
Näin ollen etäisyys kohta (P) kohtaan (Q) on antanut: Sqrt( Sq(d01) + Sq(q2-p2) ) = Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) ) = Sqrt( Sq(q0-p0) + Sq(q1-p1) + Sq(q2-p2) ).
Menetelmä pidentää etäisyyden kaava kaksi-ulotteinen tilaa kolmiulotteisuus voidaan soveltaa toistuvasti lopulta määrittää etäisyys kaava (d)-ulotteinen avaruus: Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) + ...  + Sq(qd-pd) ).
Alla oleva koodi määrittelee funktion nimeltä "Pituus" joka pakottavaa pituus on (d)-ulotteinen vektori.
Kun vektori on joutunut jättämään kotinsa kahden kohtia (d)-ulotteinen avaruus, pituus vektori edustaa välinen etäisyys nämä kaksi seikkaa.
public class VectorF64
{
    // . . .




    public double Length()
    {
        if (null == this.components)
        {
            return (0.0); // Vector empty.
        }

        int dimensions = this.Dimensions();

        double sumOfSquares = 0.0;
        for (int i = 0; i < dimensions; i++)
        {
            sumOfSquares += (this[i] * this[i]);
        }

        double length = Math.Sqrt( sumOfSquares );

        return (length);
    }




    public static double Length( VectorF64 a )
    {
        if (null == a)
        {
            return (0.0); // Vector not specified.
        }

        if (null == a.components)
        {
            return (0.0); // Vector is empty.
        }

        return (a.Length());
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of vector length:

        // A 6-dimensional vector representing a point (p):
        VectorF64 p = new VectorF640.01.02.03.04.05.0 );
        p.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )

        // A 6-dimensional vector representing a point (q):
        VectorF64 q = new VectorF64-5.04.0-3.02.0-1.00.0 );
        q.WriteLine(); // ( -5,  4, -3,  2, -1,  0 )

        // A 6-dimensional vector representing the displacement
        // from point (p) to point (q):
        VectorF64 r = q - p;
        r.WriteLine(); // ( -5,  3, -5, -1, -5, -5 )

        // The distance between point (p) and point (q)
        // in 6-dimensional space:
        double distance = r.Length();
        Log.WriteLine( distance ); // 10.4880884817015


        // . . .
    }
}

3.10 (d)-ulotteisten vektorien: piste tuote

The "dot tuote" muuntaa kaksi (d)-ulotteisten vektorien joukolle.
Alla oleva koodi pakottavaa pistettä tuote kaksi vektorit:
public class VectorF64
{
    // . . .





    public static double Dot( VectorF64 a, VectorF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (0.0); // Vector not specified.
        }

        if ((null == a.components) || (null == b.components))
        {
            return (0.0); // Vector is empty.
        }

        if (a.Dimensions() != b.Dimensions())
        {
            return (0.0); // Vectors not the same size.
        }

        int dimensions = a.Dimensions();

        double dotProduct = 0.0;
        for (int i = 0; i < dimensions; i++)
        {
            dotProduct += (a[i] * b[i]);
        }

        return (dotProduct);
    }




    // . . .
}
Niiden vektori, (A), Length(A) = Sqrt(Dot(A,A)).

3.11 (d)-ulotteisten vektorien: määritelmä "rinnakkaisten"

Vektorit (A) ja (B) ovat "rinnakkaisia," jos kaikki seuraavat ovat totta:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = A.Length()*B.Length().
Alla oleva koodi määrittelee, jos pari vektorit ovat rinnakkaisia (mahdollisesti anti-yhtenäistettyjen).
Floating-point numeroista voi kerääntyä virheitä, murto-osa rajallisuuden vuoksi tarkkuutta, ja siksi, tietokone-koodi tulisi kuulua ei-nolla toleranssit verrattaessa kelluvia-kohtien numeroihin.
Koodi sisältää esimerkiksi suvaitsevaisuuden arvoja, mutta esimerkiksi suvaitsevaisuuden arvoja ei ehkä ole tarkoituksenmukaista joitakin tehtäviä.
public class VectorF64
{
    // . . .




    public static bool Parallel( VectorF64 a, VectorF64 b )
    {
        // Smallest normalized float : 1.1754943e-38
        // Smallest normalized double: 2.2250738585072020e-308
        double nonZeroThreshold = 1.0e-38// conservative for double
        // double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
        double fractionalDifferenceThreshold = 1.0e-14// conservative

        if ((null == a) || (null == b))
        {
            return (false); // Vector is not specified.
        }

        if ((null == a.components) || (null == b.components))
        {
            return (false); // Vector is empty.
        }

        if (a.Dimensions() != b.Dimensions())
        {
            return (false); // Vectors not the same size.
        }

        double lengthA = a.Length();
        if (lengthA <= nonZeroThreshold)
        {
            return (false);
        }

        double lengthB = b.Length();
        if (lengthB <= nonZeroThreshold)
        {
            return (false);
        }

        double oneImpliesParallel =
            Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);

        double absoluteDifferenceFromOne =
            Math.Abs( oneImpliesParallel - 1.0 );

        if (absoluteDifferenceFromOne <= fractionalDifferenceThreshold)
        {
            return (true);
        }

        return (false);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of testing for parallel vectors:

        // A 6-dimensional vector:
        VectorF64 vf = new VectorF640.01.02.03.04.05.0 );
        vf.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )

        // A 6-dimensional vector:
        VectorF64 vg = new VectorF640.0-2.0-4.0-6.0-8.0-10.0 );
        vg.WriteLine(); // (   0,  -2,  -4,  -6,  -8, -10 )

        // Determine if the specified vectors are parallel
        // (or "anti-aligned"):
        bool parallel = VectorF64.Parallel( vf, vg );
        Log.WriteLine( parallel ); // True

        // Add a non-negligible displacement to a component of a vector:
        vf[0] += 1.0e-5;
        vf.WriteLine(); // ( 1E-05,     1,     2,     3,     4,     5 )

        // Determine if the specified vectors are parallel
        // (or "anti-aligned"):
        parallel = VectorF64.Parallel( vf, vg );
        Log.WriteLine( parallel ); // False


        // . . .
    }
}

3.12 (d)-ulotteisten vektorien: määritelmä "kohtisuorassa"

Vektorit (A) ja (B) ovat "kohtisuorassa," jos kaikki seuraavat ovat totta:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = 0.
Alla oleva koodi määrittelee, jos pari vektorit ovat kohtisuorassa.  Floating-point numeroista voi kerääntyä virheitä, murto-osa rajallisuuden vuoksi tarkkuutta, ja siksi, tietokone-koodi tulisi kuulua ei-nolla toleranssit verrattaessa kelluvia-kohtien numeroihin.
Koodi sisältää esimerkiksi suvaitsevaisuuden arvoja, mutta esimerkiksi suvaitsevaisuuden arvoja ei ehkä ole tarkoituksenmukaista joitakin tehtäviä.
public class VectorF64
{
    // . . .




    public static bool Perpendicular( VectorF64 a, VectorF64 b )
    {
        // Smallest normalized float : 1.1754943e-38
        // Smallest normalized double: 2.2250738585072020e-308
        double nonZeroThreshold = 1.0e-38// conservative for double
        // double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
        double fractionalDifferenceThreshold = 1.0e-14// conservative

        if ((null == a) || (null == b))
        {
            return (false); // Vector is not specified.
        }

        if ((null == a.components) || (null == b.components))
        {
            return (false); // Vector is empty.
        }

        if (a.Dimensions() != b.Dimensions())
        {
            return (false); // Vectors not the same size.
        }

        double lengthA = a.Length();
        if (lengthA <= nonZeroThreshold)
        {
            return (false);
        }

        double lengthB = b.Length();
        if (lengthB <= nonZeroThreshold)
        {
            return (false);
        }

        double zeroImpliesPerpendicular =
            Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);

        double absoluteDifferenceFromZero =
            Math.Abs( zeroImpliesPerpendicular );

        if (absoluteDifferenceFromZero <= fractionalDifferenceThreshold)
        {
            return (true);
        }

        return (false);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of testing for perpendicular vectors:

        // A 6-dimensional vector:
        VectorF64 vf2 = new VectorF640.01.02.00.04.05.0 );
        vf2.WriteLine(); // ( 0, 1, 2, 0, 4, 5 )

        // A 6-dimensional vector:
        VectorF64 vg2 = new VectorF6410.00.00.0-5.00.00.0 );
        vg2.WriteLine(); // ( 10,  0,  0, -5,  0,  0 )

        // Determine if the specified vectors are perpendicular
        bool perpendicular = VectorF64.Perpendicular( vf2, vg2 );
        Log.WriteLine( perpendicular ); // True

        // Add a non-negligible displacement to a component of a vector:
        vf2[0] += 1.0e-13;
        vf2.WriteLine(); // ( 1E-13,    1,    2,    0,    4,    5 )

        // Determine if the specified vectors are perpendicular
        perpendicular = VectorF64.Perpendicular( vf2, vg2 );
        Log.WriteLine( perpendicular ); // False


        // . . .
    }
}

3.13 Matrices

"matriisi:" A kokoelma muuttujia siten, että kukin muuttuja on ainutlaatuinen yhdistelmä "rivin" nimi ja "sarakkeen" nimi.
"maahantulon:" Vaihtuva-matriisi.
Integer-arvoja voidaan käyttää "rivi" nimet "ja" sarakkeiden nimet muuttujat matriisi.
Esimerkiksi, jos matriisi on (totalRows) rivejä ja (totalColumns) sarakkeet, sitten kokonaislukuarvoista { 0, 1, ..., (totalRows-1) } voidaan nimet, joiden tehtävänä on rivejä, ja kokonaislukuarvoista { 0, 1, ..., (totalColumns-1) } voidaan nimet, joiden tehtävänä on sarakkeita.
Näin ollen muuttujien matriisi voidaan määritellä määrittelemällä kaksi kokonaislukua, ( row, column ), jossa ilmoitetaan yhdistelmä rivi ja sarake, jotka vastaavat erityisiä muuttuja.
Koko matriisi on määritetty "(totalRows) * (totalColumns)" (tai "(totalRows) jonka (totalColumns))."
Tämä järjestys mitat on sama kuin tilauksen mitat erittelemiseksi käytetty merkinnät matriisi "(( row, column ))."
[Tämä yleissopimus on hieman harmillista, koska monet kaksiulotteinen käyttää (esimerkkejä: kuvat, kaaviot jne.) tavanomaisten yleissopimus on täsmentää mitat kuten "width * height" ja koordinoi kuin "( horizontal, vertical )" (tai "( x, y ))."
Tämä on päinvastainen järjestys mitat ja koordinaatit käytetään kuvaamaan matriisit ja niiden merkinnöistä.  ]
A-matriisin kanssa (totalRows) yhtä (totalColumns) on nimetty "aukio," muuten matriisi on nimeltään "suorakulmainen."
A matrix voidaan katsoa sisältävän joukon "rivi vektorit," jossa muuttujat kullakin rivillä on tulkittava siten, joka kuuluu vektoria.
Matriisi voidaan myös katsoa sisältävän joukon "sarakkeessa vektorit," jossa muuttujat kussakin sarakkeessa on tulkittava siten, joka kuuluu vektoria.
Matrices voi edustaa hyvin monenlaisia matemaattisia suhteita.
Merkitys matriisi, ja toimista, jotka voisivat olla tarkoituksenmukaisia käsittelystä merkinnät, matriisi, riippuu yhteydessä.
On kuitenkin olemassa perussääntöjä, matriisi aritmeettinen, jotka liittyvät useissa yhteyksissä, ja nämä perussäännöt on määritelty seuraavassa jaksossa.
An array ja (totalColumns) arvo ovat riittävät edustaa matriisi.
The array voi olla (totalRows * totalColumns) muuttujia, ja maahantulo ( row, column ) voi vastata, että jono muuttujan klo hakemisto ((totalColumns * row) + column).
Alla oleva koodi määritellään matriisi, 64-bittinen kelluvia-kohta merkinnät.
An array ja (totalColumns) arvo ovat riittävät edustaa matriisi.
Alla oleva koodi on jono ja (totalColumns) arvo sisältyvät luokkaan, vain mukavuussyistä.
Alla oleva koodi ei ole tarkoitus olla tehokasta.
A rakennetta (esimerkki: "struct", arvon tyyppi) edustavat matriisit erityisesti kiinteän mitat (esimerkkejä: 2*2, 3*3 tai 4*4) on todennäköisesti paljon tehokkaampi kuin yleinen (totalRows * totalColumns) luokan esitetään tässä.
Vaikka alla oleva koodi määrittelee matriisin kanssa kelluvia-kohta merkinnöistä, tässä artiklassa myös käyttää matriisien kanssa integer merkinnät.
Alla oleva koodi voidaan muokata helposti siten, että toteuttaa matriisien kanssa integer merkinnät.
using System;
using System.Collections.Generic;
using System.Text;

// Matrix with 64-bit floating-point entries:

public class MatrixF64
{
    private int totalRows;
    private int totalColumns;
    private double[] entries;
    // matrix[ row, column ] = entries[ (totalColumns * row) + column ]




    public int Columns()
    {
        return (this.totalColumns);
    }




    public int Rows()
    {
        return (this.totalRows);
    }




    public MatrixF64()
    {
        this.totalRows = 0;
        this.totalColumns = 0;
        this.entries = null;
    }




    public MatrixF64int rows, int columns, params double[] paramValues )
    {
        this.totalRows = 0;
        this.totalColumns = 0;
        this.entries = null;

        if (rows <= 0)
        {
            return// Specified an invalid row count.
        }
        if (columns <= 0)
        {
            return// Specified an invalid column count.
        }

        int totalEntries = (rows * columns);

        this.totalRows = rows;
        this.totalColumns = columns;
        this.entries = new double[totalEntries];

        for (int k = 0; k < totalEntries; k++)
        {
            this.entries[k] = 0.0;
        }

        if (null == paramValues)
        {
            return// No entries specified.
        }

        int totalParamValues = paramValues.Length;
        if (totalParamValues != totalEntries)
        {
            // The number of specified entries does not match the
            // total number of matrix entries.
            return;
        }

        for (int k = 0; k < totalParamValues; k++)
        {
            this.entries[k] = paramValues[k];
        }
    }




    public MatrixF64MatrixF64 other )
    {
        this.totalRows = 0;
        this.totalColumns = 0;
        this.entries = null;

        if (null == other)
        {
            return;
        }

        if
        (
               (null == other.entries)
            || (0 == other.totalRows)
            || (0 == other.totalColumns)
        )
        {
            return;
        }

        int totalEntries = (other.totalRows * other.totalColumns);

        if (other.entries.Length != totalEntries)
        {
            return;
        }

        this.totalRows = other.totalRows;
        this.totalColumns = other.totalColumns;
        this.entries = new double[totalEntries];

        for (int k = 0; k < totalEntries; k++)
        {
            this.entries[k] = other.entries[k];
        }
    }




    public double this[int row, int column]
    {
        get
        {
            if
            (
                   (this.totalRows > 0)
                && (this.totalColumns > 0)
                && (null != this.entries)
                && (row >= 0)
                && (row < this.totalRows)
                && (column >= 0)
                && (column < this.totalColumns)
            )
            {
                int k = (this.totalColumns * row) + column;
                if ((k >= 0) && (k < this.entries.Length))
                {
                    return (this.entries[k]);
                }
            }

            return (0.0);
        }

        set
        {
            if
            (
                   (this.totalRows > 0)
                && (this.totalColumns > 0)
                && (null != this.entries)
                && (row >= 0)
                && (row < this.totalRows)
                && (column >= 0)
                && (column < this.totalColumns)
            )
            {
                int k = (this.totalColumns * row) + column;
                if ((k >= 0) && (k < this.entries.Length))
                {
                    this.entries[k] = value;
                }
            }
        }
    }




    public void WriteLine( int precision )
    {
        if
        (
               (this.totalRows <= 0)
            || (this.totalColumns <= 0)
            || (null == this.entries)
        )
        {
            Log.WriteLine( String.Empty + '[' + ' ' + ']' );
            return;
        }

        // Determine the largest entry width in characters
        // so that we can make all columns an equal width.
        int largestEntryWidth = 1;
        for (int i = 0; i < this.totalRows; i++)
        {
            for (int j = 0; j < this.totalColumns; j++)
            {
                // { index [,minwidth] [:typeCode[precision]] }
                //      (minwidth<0) means left-justify
                String text = String.Format( String.Empty
                    + '{' + '0' + ':' + 'g' + precision + '}', this[i,j] );
                if (text.Length > largestEntryWidth)
                {
                    largestEntryWidth = text.Length;
                }
            }
        }

        // Print each row of the matrix.
        for (int i = 0; i < this.totalRows; i++)
        {
            Log.Write( '[' );
            for (int j = 0; j < this.totalColumns; j++)
            {
                Log.Write( ' ' );
                String text = String.Format( String.Empty
                    + '{' + '0' + ',' + largestEntryWidth + ':' + 'g'
                    + precision + '}', this[i,j] );
                Log.Write( text );
                if ((j + 1) < this.totalColumns)
                {
                    Log.Write( ',' );
                }
                else
                {
                    Log.Write( ' ' );
                }
            }
            Log.WriteLine( ']' );
        }
    }




    public void WriteLine()
    {
        const int defaultPrecision = 8;
        this.WriteLine( defaultPrecision );
    }




    // . . .




    public static void Test()
    {
        // A 5x3 matrix (5 rows x 3 columns) with
        // 64-bit floating-point entries:
        MatrixF64 m =
            new MatrixF64
            (
            53,
             0.0,  1.0,  2.0// row 0
             3.0,  4.0,  5.0// row 1
             6.0,  7.0,  8.0// row 2
             9.010.011.0// row 3
            12.013.014.0  // row 4
            );
        m.WriteLine();
        // [  0,  1,  2 ]  // row 0
        // [  3,  4,  5 ]  // row 1
        // [  6,  7,  8 ]  // row 2
        // [  9, 10, 11 ]  // row 3
        // [ 12, 13, 14 ]  // row 4

        // . . .
    }
}
"nolla matriisi:" A matrix with all entries nolla.
public class MatrixF64
{
    // . . .




    public static MatrixF64 Zero( int rows, int columns )
    {
        MatrixF64 zero = new MatrixF64( rows, columns );
        // The constructor above sets all entries to zero.
        return (zero);
    }




    // . . .




    public static void Test()
    {
        // . . .

        // An 8x2 matrix (8 rows x 2 columns) with all 16
        // 64-bit floating-point entries set to zero:
        MatrixF64 z = MatrixF64.Zero( 82 );
        z.WriteLine();
        // [ 0, 0 ]  // row 0
        // [ 0, 0 ]  // row 1
        // [ 0, 0 ]  // row 2
        // [ 0, 0 ]  // row 3
        // [ 0, 0 ]  // row 4
        // [ 0, 0 ]  // row 5
        // [ 0, 0 ]  // row 6
        // [ 0, 0 ]  // row 7

        // . . .
    }
}

3.14 Matrix lisäksi, subtraction, multiplication

Matrix lisäksi, subtraction, multiplication.
public class MatrixF64
{
    // . . .




    public static MatrixF64 operator +( MatrixF64 a, MatrixF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );

        if
        (
               (null == a.entries)
            || (null == b.entries)
            || (a.totalRows != b.totalRows)
            || (a.totalColumns != b.totalColumns)
        )
        {
            return (result);
        }

        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < a.totalColumns; j++)
            {
                result[i, j] = a[i, j] + b[i, j];
            }
        }

        return (result);
    }




    public static MatrixF64 operator -( MatrixF64 a, MatrixF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );

        if
        (
               (null == a.entries)
            || (null == b.entries)
            || (a.totalRows != b.totalRows)
            || (a.totalColumns != b.totalColumns)
        )
        {
            return (result);
        }

        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < a.totalColumns; j++)
            {
                result[i, j] = a[i, j] - b[i, j];
            }
        }

        return (result);
    }




    public static MatrixF64 operator -( MatrixF64 a )
    {
        if (null == a)
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );

        if (null == a.entries)
        {
            return (result);
        }

        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < a.totalColumns; j++)
            {
                result[i, j] = (-( a[i, j] ));
            }
        }

        return (result);
    }




    public static MatrixF64 operator *( double scale, MatrixF64 a )
    {
        if (null == a)
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );

        if (null == a.entries)
        {
            return (result);
        }

        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < a.totalColumns; j++)
            {
                result[i, j] = scale * a[i, j];
            }
        }

        return (result);
    }




    public static MatrixF64 operator *( MatrixF64 a, double scale )
    {
        if (null == a)
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, a.totalColumns );

        if (null == a.entries)
        {
            return (result);
        }

        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < a.totalColumns; j++)
            {
                result[i, j] = scale * a[i, j];
            }
        }

        return (result);
    }




    public static MatrixF64 operator *( MatrixF64 a, MatrixF64 b )
    {
        if ((null == a) || (null == b))
        {
            return (null);
        }

        MatrixF64 result = MatrixF64.Zero( a.totalRows, b.totalColumns );

        // The number of columns of the first matrix must be equal
        // to the number of rows of the second matrix.
        if
        (
               (null == a.entries)
            || (null == b.entries)
            || (a.totalColumns != b.totalRows)
        )
        {
            return (result);
        }

        // Entry (i,j) of the result is equal to the dot product
        // of row (i) of (a) and column (j) of (b).
        for (int i = 0; i < a.totalRows; i++)
        {
            for (int j = 0; j < b.totalColumns; j++)
            {
                double dotProduct = 0.0;
                for (int k = 0; k < a.totalColumns; k++)
                {
                    dotProduct += (a[i, k] * b[k, j]);
                }
                result[i, j] = dotProduct;
            }
        }

        return (result);
    }




    // . . .




    public static void Test()
    {
        // . . .

        // Examples of matrix addition, subtraction, and multiplication:

        MatrixF64 a =
            new MatrixF64
            (
            35,
             0.0,  1.0,  2.0,  3.0,  4.0// row 0
             5.0,  6.0,  7.0,  8.0,  9.0// row 1
            10.011.012.013.014.0  // row 2
            );

        MatrixF64 b =
            new MatrixF64
            (
            35,
             4.0-3.0,   2.0,  -1.0,  0.0// row 0
            -9.0,  8.0,  -7.0,   6.0-5.0// row 1
            14.0-13.012.0-11.010.0  // row 2
            );

        MatrixF64 c =
            new MatrixF64
            (
            53,
             0.0,  1.0,  2.0// row 0
             3.0,  4.0,  5.0// row 1
             6.0,  7.0,  8.0// row 2
             9.010.011.0// row 3
            12.013.014.0  // row 4
            );

        MatrixF64 result = new MatrixF64();

        result = a + b;
        result.WriteLine();
        // [  4, -2,  4,  2,  4 ]
        // [ -4, 14,  0, 14,  4 ]
        // [ 24, -2, 24,  2, 24 ]

        result = a - b;
        result.WriteLine();
        // [ -4,  4,  0,  4,  4 ]
        // [ 14, -2, 14,  2, 14 ]
        // [ -4, 24,  0, 24,  4 ]

        result = -a;
        result.WriteLine();
        // [   0,  -1,  -2,  -3,  -4 ]
        // [  -5,  -6,  -7,  -8,  -9 ]
        // [ -10, -11, -12, -13, -14 ]

        result = 3.0 * a;
        result.WriteLine();
        // [  0,  3,  6,  9, 12 ]
        // [ 15, 18, 21, 24, 27 ]
        // [ 30, 33, 36, 39, 42 ]

        result = a * c; // (3x5) * (5x3) = (3x3)
        result.WriteLine();
        // [  90, 100, 110 ]
        // [ 240, 275, 310 ]
        // [ 390, 450, 510 ]

        result = c * a; // (5x3) * (3x5) = (5x5)
        result.WriteLine();
        // [  25,  28,  31,  34,  37 ]
        // [  70,  82,  94, 106, 118 ]
        // [ 115, 136, 157, 178, 199 ]
        // [ 160, 190, 220, 250, 280 ]
        // [ 205, 244, 283, 322, 361 ]

        // . . .
    }
}
"identiteetti matriisi:" A square matrix (Rivit tasavertaisina yhteensä sarakkeet) merkinnät yhtä (1), lävistäjä (merkinnät peräkkäin hakemisto yhtä sen sarakkeen indeksi), sekä kaikki muut merkinnät yhtä (0).
Jos neliö matriisi, (M), kerrotaan oma "identiteetti matriisi," (I), sama määrä rivit (ja sarakkeet), tuote on yhtä (M).
Kertomalla (I) jonka (M) tuottaa myös tuotteen yhtä (M).
Näin ollen "identiteetti matriisi" on analoginen määrä "1" varten kertomalla numerot (scalars).
Alla oleva koodi luo identiteetin matriisi, joilla on tietty määrä rivejä.
public class MatrixF64
{
    // . . .




    public static MatrixF64 Identity( int rows )
    {
        MatrixF64 identity = MatrixF64.Zero( rows, rows );
        for (int i = 0; i < rows; i++)
        {
            identity[i, i] = 1.0;
        }
        return (identity);
    }




    // . . .




    public static void Test()
    {
        // . . .

        // Examples of multiplying by an identity matrix:

        MatrixF64 identity3x3 = MatrixF64.Identity( 3 );
        // [ 1, 0, 0 ]
        // [ 0, 1, 0 ]
        // [ 0, 0, 1 ]

        MatrixF64 s3x3 =
            new MatrixF64
            (
            33,
            0.01.02.0// row 0
            3.04.05.0// row 1
            6.07.08.0  // row 2
            );

        result = s3x3 * identity3x3;
        result.WriteLine();
        // [ 0, 1, 2 ]
        // [ 3, 4, 5 ]
        // [ 6, 7, 8 ]
        // (the same as s3x3)

        result = identity3x3 * s3x3;
        result.WriteLine();
        // [ 0, 1, 2 ]
        // [ 3, 4, 5 ]
        // [ 6, 7, 8 ]
        // (the same as s3x3)

        // . . .
    }
}

3.15 Matrix: LU factoring; back-korvaushoitoa

"Matrix LU factoring:" A menettely, joka muuntaa neliön matriisi, (M), kaksi uutta neliön matriisit, (L) ja (U), joilla on saman kokoinen kuin (M) siten, että (L) * (U) = (M), ja sellainen, että matriisi (U) on "ylempi kolmiomainen" (kaikki merkinnät alle lävistäjä on nolla) ja matriisi (L) on "pienempi kolmiomainen" (kaikki merkinnät yläpuolella lävistäjä on nolla).
Matrix LU factoring voidaan käyttää osana laajempaa menettelyä ratkaista järjestelmän yhtälöt, tai löytää käänteistä matriisi, tai löytää tekijä matriisi.
Matrix LU factoring on vaihtoehto, "Gauss-Jordan poistamisen menettely.
Gauss-Jordan poistaminen vaatii järjestelmän yhtälöt (A)*(x)=(b), kun taas LU factoring edellyttää vain matriisi (A).
Myös sen jälkeen, kun määritetään LU factoring-, matriisi (A), se on erittäin helppo määrittää (x) antanut mitään (b).
Menettely, ratkaisee vektori (x) vuonna (A)*(x)=(b), koska (b) ja LU factoring (L)*(U)=(A), koskee menettelyä, joka on nimetty "takaisin-korvaushoitoa."
Alla oleva koodi sisältää menettelyn laskemalla LU tekijät kaikista square, ei-yksikkö matriisi.
Alla oleva koodi sisältää menettelyn tekee LU takaisin-korvaushoitoa.
Varoitus: Tietokoneen koodin alla pakottavaa että L ja U tekijät, rivi-permuted versio tietyn matriisi.
Also, L ja U matriisi tulokset on yhdistetty yhdelle ainoalle output matriisi.
public class MatrixF64
{
    // . . .




    public static void FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
        (
        MatrixF64 originalMatrix,
        ref MatrixF64 LUFactorsMatrix,
        ref int[] rowPermutationOfOriginalMatrix,
        ref bool rowExchangeParityIsOdd
        )
    {
        // ''LU factoring'' involves factoring a square matrix (M) in to a
        // lower-triangular matrix (L), and an upper-triangular matrix (U),
        // such that (L)*(U) = (M).
        //
        // However, the specified matrix (originalMatrix) might not be
        // optimal for direct LU factoring, due to the locations of extreme
        // values in the matrix.  Therefore, this function instead implicitly
        // factors a row-permuted version of originalMatrix, where the
        // permutation of rows is determined by the values in the specified
        // matrix.  The specific row permutation selected by this function is
        // returned in an array of row indices (rowPermutationOfOriginalMatrix).
        // The resulting (L) and (U) factors are merged in to a single
        // output matrix (LUFactorsMatrix).  Therefore:
        //
        // (L part of LUFactorsMatrix) * (U part of LUFactorsMatrix)
        //   = (originalMatrix with rows permuted according to
        //           rowPermutationOfOriginalMatrix).
        //
        // Although factoring a row-permuted version of originalMatrix
        // makes it more difficult to interpret the results of this function,
        // the resulting LU factoring is likely to be more accurate.  In a
        // sense, this function indicates (via rowPermutationOfOriginalMatrix)
        // how to permute the rows of originalMatrix to be able to produce
        // the most accurate LU factoring directly, and this function produces
        // that factoring (via the LUFactorsMatrix output).
        //
        // When using the (L) and (U) matrices (merged in to LUFactorsMatrix)
        // to solve a system of equations, it is necessary to permute the rows
        // of the solution vector of the system of equations according to
        // rowPermutation.
        //
        // The output matrix (LUFactorsMatrix) is a combination of
        // the (L) and (U) matrices:
        //
        // To form the (L) matrix from (LUFactorsMatrix):
        //      assume (0) for entries above the diagonal,
        //      assume (1) for entries on    the diagonal,
        //      and use (LUFactorsMatrix) entries below the diagonal.
        //
        // To form the (U) matrix from (LUFactorsMatrix):
        //      assume (0) for entries below the diagonal,
        //      and use (LUFactorsMatrix) entries on and above the diagonal.
        //
        // The output array (rowPermutationOfOriginalMatrix) indicates how the
        // rows of the original matrix have implicitly (not actually) been
        // permuted.
        //
        // The output boolean (rowExchangeParityIsOdd) indicates if the parity
        // of the permutation of rows is odd.
        //
        // This implementation is partly based on pseudo-code appearing in
        // ''Introduction to Algorithms'' (Cormen; Lieserson; Rivest;
        // 24th printing, 2000; MIT Press; ISBN 0-262-03141-8).
        // See the section named ''Overview of LUP decomposition'', in
        // chapter 31 (''Matrix Operations'').  The implementation here follows
        // the ''LUP-Decomposition'' pseudo-code appearing in a section named
        // ''Computing an LUP decomposition''.
        //
        // This implementation also uses ideas found in the implementation of
        // ''ludcmp'' in the book ''Numerical recipes in C : The art of
        // scientific computing'' (Press; Teukolsky; Vetterling; Flannery;
        // second edition; 1996 reprinting; Cambridge University Press).
        // The overall loop structure here resembles that of ''ludcmp''.
        // The idea of determining and caching row scale factors in advance of
        // finding pivots is used here.  The method in ''ludcmp'' to avoid zero
        // pivot values has been modified here to handle excessively-small
        // pivot values, too.  HOWEVER, the row permutation indices produced by
        // the following implementation is a true permutation of
        // {0,1,...,(totalRows-1)}, whereas ''ludcmp'' (and ''lubksb'')
        // interpret their ''permutation indices'' as swaps to perform
        // (roughly, for each (i), swap b[ i ] and b[ indx[i] ]).  So, the
        // following implementation of LU-factoring is not directly compatible
        // with ''ludcmp'' or ''lubksb''.  Also, the following procedure
        // does not destroy the original matrix (unlike ''ludcmp'').

        double singularMatrixIfMaxRowElementIsLessThanThis = (1.0e-19);
        double forcePivotsToHaveAtLeastThisAbsoluteValue = (1.0e-19);

        LUFactorsMatrix = null;
        rowPermutationOfOriginalMatrix = null;
        rowExchangeParityIsOdd = false;

        if (null == originalMatrix)
        {
            return// No matrix specified.
        }

        if
        (
               (originalMatrix.totalRows <= 0)
            || (originalMatrix.totalColumns <= 0)
            || (null == originalMatrix.entries)
        )
        {
            return// Matrix is empty.
        }

        if (originalMatrix.totalRows != originalMatrix.totalColumns)
        {
            return// Matrix is not square.
        }


        // Duplicate the original matrix
        LUFactorsMatrix = new MatrixF64( originalMatrix );


        // (Lines 2-3 of LUP-Decomposition)
        // Initialize the row permutation array to the identity
        // permutation.
        rowPermutationOfOriginalMatrix = new int[LUFactorsMatrix.totalRows];
        for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
        {
            rowPermutationOfOriginalMatrix[i] = i;
        }


        // For each row, determine the largest absolute value of
        // the row elements, and use the reciprocal as the scale for
        // that row.
        VectorF64 rowScales = VectorF64.Zero( LUFactorsMatrix.totalRows );
        for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
        {
            double largestElementAbsoluteValueInRow = 0.0;
            for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
            {
                double absoluteElementValue =
                    Math.Abs( LUFactorsMatrix[i, j] );

                if (absoluteElementValue >
                    largestElementAbsoluteValueInRow)
                {
                    largestElementAbsoluteValueInRow =
                        absoluteElementValue;
                }
            }
            if (largestElementAbsoluteValueInRow <
                singularMatrixIfMaxRowElementIsLessThanThis)
            {
                return// Matrix is singular
            }
            rowScales[i] = (1.0 / largestElementAbsoluteValueInRow);
        }


        // (Lines 4-18 of LUP-Decomposition)
        // Go through the columns of the matrix.
        for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
        {
            // (Lines 17-18 of LUP-Decomposition)
            // (or equation (2.3.12) of NR)
            for (int i = 0; i < j; i++)
            {
                double sum = LUFactorsMatrix[i, j];
                for (int k = 0; k < i; k++)
                {
                    sum -= (LUFactorsMatrix[i, k] * LUFactorsMatrix[k, j]);
                }
                LUFactorsMatrix[i, j] = sum;
            }

            // Go through all remaining rows and find the best pivot.
            double largestScaledSum = 0.0;
            int rowIndexOfLargestScaledSum = j;
            for (int i = j; i < LUFactorsMatrix.totalRows; i++)
            {
                // (equation (2.3.13) of NR)
                double sum = LUFactorsMatrix[i, j];
                for (int k = 0; k < j; k++)
                {
                    sum -= (LUFactorsMatrix[i, k] * LUFactorsMatrix[k, j]);
                }
                LUFactorsMatrix[i, j] = sum;

                double scaledSum = rowScales[i] * Math.Abs( sum );
                if (scaledSum >= largestScaledSum)
                {
                    largestScaledSum = scaledSum;
                    rowIndexOfLargestScaledSum = i;
                }
            }

            // If indeed we found a better pivot, then exchange rows.
            if (j != rowIndexOfLargestScaledSum)
            {
                // (Line 12 of LUP-Decomposition)
                // Exchange the row permutation indices
                int tempRowIndex = rowPermutationOfOriginalMatrix[j];
                rowPermutationOfOriginalMatrix[j] =
                    rowPermutationOfOriginalMatrix[rowIndexOfLargestScaledSum];
                rowPermutationOfOriginalMatrix[rowIndexOfLargestScaledSum] =
                    tempRowIndex;

                // (Lines 13-14 of LUP-Decomposition)
                // Exchange the elements of the rows
                for (int k = 0; k < LUFactorsMatrix.totalColumns; k++)
                {
                    double temp = LUFactorsMatrix[rowIndexOfLargestScaledSum, k];
                    LUFactorsMatrix[rowIndexOfLargestScaledSum, k] =
                        LUFactorsMatrix[j, k];
                    LUFactorsMatrix[j, k] = temp;
                }

                // Exchange the row scale factors
                double scaleFactor =
                    rowScales[rowIndexOfLargestScaledSum];
                rowScales[rowIndexOfLargestScaledSum] = rowScales[j];
                rowScales[j] = scaleFactor;

                // Invert the overall row exchange parity
                rowExchangeParityIsOdd = (!(rowExchangeParityIsOdd));
            }

            // Force the pivot element to have at least a certain
            // absolute value.
            if (Math.Abs( LUFactorsMatrix[j, j] ) <
                forcePivotsToHaveAtLeastThisAbsoluteValue)
            {
                if (LUFactorsMatrix[j, j] < 0.0)
                {
                    LUFactorsMatrix[j, j] =
                        (-(forcePivotsToHaveAtLeastThisAbsoluteValue));
                }
                else
                {
                    LUFactorsMatrix[j, j] =
                        forcePivotsToHaveAtLeastThisAbsoluteValue;
                }
            }

            // If not the final column, then divide all column elements
            // below the diagonal by the pivot element, matrixLU[j,j].
            // (Lines 15-16 of LUP-Decomposition)
            if (j != (LUFactorsMatrix.totalColumns - 1))
            {
                double reciprocalOfPivot = (1.0 / LUFactorsMatrix[j, j]);
                for (int i = (j + 1); i < LUFactorsMatrix.totalRows; i++)
                {
                    LUFactorsMatrix[i, j] *= reciprocalOfPivot;
                }
            }
        }
    }




    public static void LUBacksubstitution
        (
        MatrixF64 LUFactorsMatrix,
        int[] rowPermutationOfOriginalMatrix,
        VectorF64 givenProductVector,
        ref VectorF64 solutionVector
        )
    {
        // This implementation is based on pseudo-code appearing in
        // ''Introduction to Algorithms'' (Cormen; Lieserson; Rivest;
        // 24th printing, 2000; MIT Press; ISBN 0-262-03141-8).
        // See the section named ''Overview of LUP decomposition'', in
        // chapter 31 (''Matrix Operations'').  The implementation here
        // follows the ''LUP-Solve'' pseudo-code appearing in a
        // section named ''forward and back substitution''.

        solutionVector = null;

        if (null == LUFactorsMatrix)
        {
            return// No matrix specified.
        }

        if (null == rowPermutationOfOriginalMatrix)
        {
            return// No permutation specified.
        }

        if (null == givenProductVector)
        {
            return// No product vector specified.
        }

        if
        (
               (null == LUFactorsMatrix.entries)
            || (LUFactorsMatrix.totalRows <= 0)
            || (LUFactorsMatrix.totalColumns <= 0)
        )
        {
            return// Matrix is empty.
        }

        if (LUFactorsMatrix.totalRows !=
            LUFactorsMatrix.totalColumns)
        {
            return// Matrix is not square.
        }

        if (givenProductVector.Dimensions() !=
            LUFactorsMatrix.totalRows)
        {
            return// Product vector size not equal to matrix row count.
        }


        // Copy the product vector in to the result.
        solutionVector = new VectorF64( givenProductVector );


        // (See LUP-Solve, lines 2-3)
        for (int i = 0; i < LUFactorsMatrix.totalRows; i++)
        {
            double sum =
                givenProductVector[rowPermutationOfOriginalMatrix[i]];
            for (int j = 0; j < i; j++)
            {
                sum -= (LUFactorsMatrix[i, j] * solutionVector[j]);
            }
            solutionVector[i] = sum;
        }


        // (See LUP-Solve, lines 4-5)
        for (int i = (LUFactorsMatrix.totalRows - 1); i >= 0; i--)
        {
            double sum = solutionVector[i];
            for
            (
                int j = (i + 1);
                j < LUFactorsMatrix.totalColumns;
                j++
            )
            {
                sum -= (LUFactorsMatrix[i, j] * solutionVector[j]);
            }
            double diagonalElement = LUFactorsMatrix[i, i];
            if (diagonalElement != 0.0)
            {
                solutionVector[i] = (sum / diagonalElement);
            }
        }
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of LU factoring and back-substitution:

        MatrixF64 a3x3 =
            new MatrixF64
            (
                33,
                0.01.02.0// row 0
                3.04.05.0// row 1
                6.07.08.0  // row 2
            );

        int[] rowPermutationOfOriginalMatrix = null;
        bool rowInterchangeParityIsOdd = false;
        MatrixF64 a3x3LU = null;
        MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
        (
            a3x3,
            ref a3x3LU,
            ref rowPermutationOfOriginalMatrix,
            ref rowInterchangeParityIsOdd
        );

        a3x3LU.WriteLine();
        // [     6,     7,     8 ]
        // [     0,     1,     2 ]
        // [   0.5,   0.5, 1e-19 ]
        // The matrix above is a combination of the L and U
        // matrices. The L matrix is 0 above the diagonal,
        // 1 on the diagonal, and the shown values below the
        // diagonal.  The U matrix is 0 below the diagonal,
        // and the shown values on and above the diagonal.
        // This LU factoring is of a ROW-PERMUTED version
        // of the original matrix.

        // The following L and U matrices are manually formed
        // by inspecting the LU factoring matrix above.
        MatrixF64 L3x3 =
            new MatrixF64
            (
                33,
                1.00.00.0// row 0
                0.01.00.0// row 1
                0.50.51.0  // row 2
            );

        MatrixF64 U3x3 =
            new MatrixF64
            (
                33,
                6.07.08.0// row 0
                0.01.02.0// row 1
                0.00.00.0  // row 2
            );

        // The product (L)*(U) produces a ROW-PERMUTED version
        // of the original matrix:
        result = L3x3 * U3x3;
        result.WriteLine( 4 );
        // [ 6, 7, 8 ]
        // [ 0, 1, 2 ]
        // [ 3, 4, 5 ]

        VectorF64 b3x1 = new VectorF641.02.03.0 );
        VectorF64 x3x1 = null;

        MatrixF64.LUBacksubstitution
        (
            a3x3LU,
            rowPermutationOfOriginalMatrix,
            b3x1,
            ref x3x1
        );

        // Solution vector
        x3x1.WriteLine();
        // ( -0.66666667,           1,           0 )
        // Both the given b3x1 and this x3x1 are relative to the
        // original matrix, a3x3.  The a3x3LU for a ROW-PERMUTED
        // version of a3x3, but LUBacksubstitution accepts a
        // non-permuted product vector (e.g., b3x1) and produces
        // a non-permuted solution vector (e.g., x3x1).

        // Check solution by multiplying the original matrix a3x3
        // by the solution vector x3x1, to get a product vector.
        VectorF64 checkb3x1 = a3x3 * x3x1;
        checkb3x1.WriteLine();
        // ( 1, 2, 3 )
        // This matches the b3x1 vector we specified above, so
        // the solution is valid.


        // . . .
    }
}

3.16 Matrix: tekijä

"tekijä:" A funktio, joka muuntaa minkä tahansa neliön (n * n) matriisi (A) joukkoon, det(A) siten, että:
(1) Jos matriisi (B) tulokset vaihtamasta kahdessa rivissä, tai kaksi saraketta, jonka matriisi (A), sitten det(B) = (-(det(A)));
(2) Jos matriisi (B) tuloksia kertomalla mitä tahansa rivi tai sarake, jonka matriisi (A), jonka numero (c), sitten det(B) = c * det(A);
(3) Jos matriisi (B) tuloksia lisäämällä useita yhden rivin toiselle riville, tai lisäämällä useita yhden sarakkeen toinen sarake, sitten det(B) = det(A).
(4) Jos (A) on upper-triangular matrix (A[i,j]=0 kaikkien (i>j)) tai alemman-triangular matrix (A[i,j]=0 kaikkien (i<j)), sitten det(A) = (A[0,0] * A[1,1] * ...  * A[n-1,n-1]);
(Esimerkiksi, tekijä, joka identiteetti matriisi on yksi; det(I) = 1.)
Säännöt (1), (2), ja (3), voidaan käyttää, on prosessin nimeltä "Gaussian poistamista, muuntaa kaikki neliö matriisi, joka triangular matrix.
Työjärjestyksen (4) voidaan laskea tekijä, joka triangular matrix.
Muodollinen määritelmä, jonka "tekijä:"
Let M[n](K) ilmi asettaa kaikkien (n * n) matriisit yli alalla (K).
Tämä "tekijä" on ainutlaatuinen tehtävä (F) sellainen, että F:M[n](K) --> K kaksi attribuuttia:
(1) F on vaihtuen multilinear osalta sarakkeet (tai rivit), ja
(2) F( I ) = 1.
A "multilinear" funktio (D) on (n * n) matriisi (A) voidaan kirjoittaa seuraavasti: D(A) = Sum( A[0,k[0]] * A[1,k[1]] * ...  * A[n-1,k[n-1]] * D( e[k[0]], e[k[1]], ..., e[k[n-1]] ) ), jos summa on ottanut haltuunsa kaikki (n^n) yhdistelmiä 0 <= k[i] <= (n-1), ja jos e[j] edustaa rivi (j), identiteetti matriisi.
Tällainen toiminto voi luonnehtia arvojen D( e[k[0]], e[k[1]], ..., e[k[n-1]] ).
"Vaihdettaisiin multilinear" funktio on multilinear funktio, (D) siten, että D( ..., e[i], ..., e[i], ...  ) = 0, ja D( ..., e[i], e[j], ...  ) = (-( D( ..., e[j], e[i], ...  ) )).
Näin ollen vaihto sarakkeet (tai rivit) muutokset merkin funktio.
Myös termi D( e[k[0]], ..., e[k[n-1]] ) on nolla, jos yhdistelmä k[i] arvot eivät osallistu kaikki ainutlaatuisia arvoja, jos asetettuja arvoja ei ole permutation, numerot {0,1,...,(n-1)}.
Vuokraamo D( I ) = 1 (D( e[0], e[1], ..., e[n-1] ) = 1), yhdessä vaihtuen multilinear attribuutit edellä kuvattu tarkoittaa sitä, että kaikki arvot vuorottelulla multilinear funktio D( e[k[0]], e[k[1]], ..., e[k[n-1]] ) voidaan määrittää.
Funktion tulee olla muu kuin nolla vain, jos joukko k[i] arvot on permutation, {0,1,...,(n-1)}, ja se on suuruusluokkaa yksi, jos se ei ole nolla, ja merkki on useita vaihtosopimuksia tarvitse muuntaa permutation, identiteetin permutation.
Arvo ratkaiseva tekijä, joka (n * n) matriisi (A) voidaan computed lisäämällä enintään tuotteiden muodossa (sgn(p) * A[0,p[0]] * A[1,p[1]] * ...  * A[(n-1),p[n-1]]) jokaisella permutation (p), numerot {0,1,2,...,(n-1)}.
Termi (sgn(p)) Kristillisdemokraattien "allekirjoitus" (tai swap-count) permutation (p), jossa (sgn(p)) on yhtä (+1) jos (p) on "jopa permutation," ja se on sama (-1) jos (p) on "pariton permutation."
Koska on olemassa (n!) permutaatioista, numerot {0,1,2,...,(n-1)}, tämä kaava on (n!) summands.
Muut menettelyt computing ratkaiseva (esimerkkejä: ne, joihin Gaussian poistamisesta tai LU factoring, tai laajennusta alaikäiset jne.) implisiittisesti compute hierarkia välituotteiden määrät, joiden avulla nämä menettelyt laskea tekijä on järjestyksessä (n^3) vaiheet.
Jos tekijä matriisi on nolla, matriisi ei ole käänteistä.
Jos tekijä matriisi on muu kuin nolla, matriisi on käänteinen.
Jos matriisi edustaa kertoimia lineaarinen järjestelmä yhtälöt, ja tekijä, että matriisi on nolla, niin järjestelmän yhtälöt ei ole ainutlaatuinen ratkaisu.
Jos matriisi edustaa kertoimia lineaarinen järjestelmä yhtälöt, ja tekijä, että matriisi ei ole nolla, niin järjestelmän yhtälöt on ainutlaatuinen ratkaisu.
Alla oleva koodi sisältää menettelyt computing ratkaiseva minkä tahansa neliön matriisi.
Determinants for 1*1, 2*2, 3*3, ja 4*4 matriisit ovat computed nimenomaisella kaavoja.
Käyttämällä selkeitä kaavoja laskea taustatekijät pienten matriisien todennäköisesti laskea tuloksia nopeammin kuin käyttämällä yleisen menettelyn laskea näitä taustatekijöitä.
Menettely yleisen tapauksessa käyttää LU factoring, mutta on olemassa monia muita menetelmiä computing taustatekijöihin.
public class MatrixF64
{
    // . . .




    private double Determinant1x1()
    {
        if
        (
               (this.totalRows != 1)
            || (this.totalColumns != 1)
            || (null == this.entries)
        )
        {
            return (0.0);
        }

        // The determinant of a 1x1 matrix is simply
        // the value of the single element.
        return ( this[0,0] );
    }




    private double Determinant2x2()
    {
        if
        (
               (this.totalRows != 2)
            || (this.totalColumns != 2)
            || (null == this.entries)
        )
        {
            return (0.0);
        }

        return
        (
        + this[0,0] * this[1,1]

        - this[0,1] * this[1,0]
        );
    }




    private double Determinant3x3()
    {
        if
        (
               (this.totalRows != 3)
            || (this.totalColumns != 3)
            || (null == this.entries)
        )
        {
            return (0.0);
        }

        return
        (
        + this[0,0] * this[1,1] * this[2,2]
        + this[0,1] * this[1,2] * this[2,0]
        + this[0,2] * this[1,0] * this[2,1]

        - this[0,0] * this[1,2] * this[2,1]
        - this[0,1] * this[1,0] * this[2,2]
        - this[0,2] * this[1,1] * this[2,0]
        );
    }




    private double Determinant4x4()
    {
        if
        (
               (this.totalRows != 4)
            || (this.totalColumns != 4)
            || (null == this.entries)
        )
        {
            return (0.0);
        }

        return
        (
        + this[00] * this[11] * this[22] * this[33]
        + this[00] * this[12] * this[23] * this[31]
        + this[00] * this[13] * this[21] * this[32]

        + this[01] * this[10] * this[23] * this[32]
        + this[01] * this[12] * this[20] * this[33]
        + this[01] * this[13] * this[22] * this[30]

        + this[02] * this[10] * this[21] * this[33]
        + this[02] * this[11] * this[23] * this[30]
        + this[02] * this[13] * this[20] * this[31]

        + this[03] * this[10] * this[22] * this[31]
        + this[03] * this[11] * this[20] * this[32]
        + this[03] * this[12] * this[21] * this[30]

        - this[00] * this[11] * this[23] * this[32]
        - this[00] * this[12] * this[21] * this[33]
        - this[00] * this[13] * this[22] * this[31]

        - this[01] * this[10] * this[22] * this[33]
        - this[01] * this[12] * this[23] * this[30]
        - this[01] * this[13] * this[20] * this[32]

        - this[02] * this[10] * this[23] * this[31]
        - this[02] * this[11] * this[20] * this[33]
        - this[02] * this[13] * this[21] * this[30]

        - this[03] * this[10] * this[21] * this[32]
        - this[03] * this[11] * this[22] * this[30]
        - this[03] * this[12] * this[20] * this[31]
        );
    }




    public double Determinant()
    {
        if
        (
               (this.totalRows <= 0)
            || (this.totalColumns <= 0)
            || (null == this.entries)
        )
        {
            return (0.0); // Matrix is empty.
        }

        if (this.totalRows != this.totalColumns)
        {
            // Matrix is not square
            return (0.0);
        }

        // Simple cases
        if (1 == this.totalRows) { return (this.Determinant1x1()); }
        if (2 == this.totalRows) { return (this.Determinant2x2()); }
        if (3 == this.totalRows) { return (this.Determinant3x3()); }
        if (4 == this.totalRows) { return (this.Determinant4x4()); }

        int[] rowPermutationOfOriginalMatrix = null;
        bool rowExchangeParityIsOdd = false;
        MatrixF64 originalMatrix = new MatrixF64this );
        MatrixF64 LUFactorsMatrix = null;

        MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
            (
            originalMatrix,
            ref LUFactorsMatrix,
            ref rowPermutationOfOriginalMatrix,
            ref rowExchangeParityIsOdd
            );

        if ((null == LUFactorsMatrix)
            || (null == rowPermutationOfOriginalMatrix))
        {
            return (0.0);
        }

        double determinant = 1.0;
        if (true == rowExchangeParityIsOdd)
        {
            determinant = (-1.0);
        }
        for (int j = 0; j < LUFactorsMatrix.totalColumns; j++)
        {
            determinant *= LUFactorsMatrix[j, j];
        }
        return (determinant);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Examples of matrix determinants:

        MatrixF64 d2x2 =
            new MatrixF64
            (
            22,
             2.0,  5.0// row 0
            -4.0-7.0  // row 1
            );
        double detd2x2 = d2x2.Determinant();
        Log.WriteLine( detd2x2 );
        // detd2x2 = 6

        MatrixF64 d3x3 =
            new MatrixF64
            (
            33,
             2.0,  5.07.0// row 0
            -4.0-1.06.0// row 1
             9.0,  8.03.0  // row 2
            );
        double detd3x3 = d3x3.Determinant();
        Log.WriteLine( detd3x3 );
        // detd3x3 = 67

        MatrixF64 d4x4 =
            new MatrixF64
            (
            44,
              7.0-5.0,  2.04.0// row 0
              3.0,  2.0,  6.03.0// row 1
             -9.0,  8.0-3.02.0// row 2
              5.0,  3.0,  2.05.0  // row 3
            );
        double detd4x4 = d4x4.Determinant();
        Log.WriteLine( detd4x4 );
        // detd4x4 = 1457


        // . . .
    }
}

3.17 (d)-ulotteisten vektorien: cross tuote

"eri tuotetta:" A toiminto liittyy johonkin (d)-ulotteinen tila, joka muuntaa tilattu luettelo (d-1) (d)-ulotteisten vektorien, { A(0), A(1), ..., A(d-2) }, joka (d)-ulotteinen vektori siten, että funktio on määritteet alla:
(1) Jos A(i)=0 (nolla vektori), mahdolliset 0 <= i <= (d-2), sitten Cross( A(0), A(1), ..., A(d-2) )=0 (nolla vektori).
Poikkileikkaus tuote, joka tilataan luettelon vektorit on nolla, jos kaikki vektorin, että luettelo on nolla;
(2) Jos jokin pari vektorit, A(i) ja A(j), kaikki (i!=j) kanssa 0 <= i <= (d-2) ja 0 <= j <= (d-2), ovat rinnakkaisia (Abs(Dot(A(i),A(j))) = Length(A(i)) * Length(A(j))), sitten Cross( A(0), A(1), ..., A(d-2) )=0 (nolla vektori).
Poikkileikkaus tuote, joka tilataan luettelon vektorit on nolla, jos minkä tahansa kahden vektorit kyseiseen luetteloon ovat rinnakkain;
(3) Jos jokainen vektori A(i) ei ole nolla, ja jos A(i) ei ole samanaikaisesti A(j) kaikkien (i!=j) kanssa 0 <= i <= (d-2) ja 0 <= j <= (d-2), sitten B = Cross( A(0), A(1), ..., A(d-2) ) on sellainen, että Dot(A(i),B)=0 kaikkien 0 <= i <= (d-2).
Jos rajat tuote, joka tilataan luettelon vektoreita ei ole nolla, niin rajat tuote tulos on kohtisuorassa jokaista vektorin tilatulle luettelo vektoreita;
(4) Jos (c) on numeerinen arvo, sitten Cross( (c * A(0)), A(1), ..., A(d-2) ) = Cross( A(0), (c * A(1)), ..., A(d-2) ) = ...  = Cross( A(0), A(1), ..., (c * A(d-2)) ) = c * Cross( A(0), A(1), ..., A(d-2) ).
Koska tilattu luettelo vektorit, rajat tuote on tilattu luettelo vektorien kanssa jokin vektori kerrotaan tietty numeerinen arvo vastaa kertomalla eri tuote on tilattu luettelo vektorit, jonka numeerinen arvo;
(5) Koska kaksi lukua (i) ja (j), jossa (i!=j) ja 0 <= i <= (d-2) ja 0 <= j <= (d-2), ja tilata luettelon (d-1) (d)-ulotteisten vektorien, { A(0), A(1), ..., A(d-2) }, ja toinen tilata luettelon (d-1) (d)-ulotteisten vektorien, { B(0), B(1), ..., B(d-2) } siten, että B(k) = A(k) kaikkien ((k != i) && (k != j)) kanssa 0 <= k <= (d-2), ja sellainen, että B(i) = A(j) ja B(j) = A(i), sitten Cross( A(0), A(1), ..., A(d-2) ) = (-1) * Cross( B(0), B(1), ..., B(d-2) ).
Jos rajat tuote, joka tilataan luettelon vektoreita ei ole nolla, niin että rajat tuote on päinvastoin merkki rajat tuote, että sama tilata luettelon vektorit lukuun ottamatta täsmälleen kaksi vektorit vaihdetaan (sivuttaa).
Koska perusteella vektorit e(k), 0 <= k <= (d-1), (d)-ulotteinen avaruus, rajat tuote, joka tilataan luettelon (d-1) vektorit voidaan computed laskemalla ratkaisevasti siihen (d*d) matriisi alla:
  e(0),        e(1),      ...,     e(d-1),
A( 0 )[0],   A( 0 )[1],   ...,   A( 0 )[d-1],
A( 1 )[0],   A( 1 )[1],   ...,   A( 1 )[d-1],
...,
A(d-2)[0],   A(d-2)[1],   ...,   A(d-2)[d-1]
Sen tekijä, että matriisi ei olla useita, mutta sen sijaan on vektori, jossa tulee olemaan numeeriset kertoimet, (d) perusteella vektorit.
For kaksiulotteisessa avaruudessa, ja vektorin A = ( ax, ay ):
Cross( A )

= Determinant
    (
          e(x),    e(y),
           ax,      ay
    )

=   ay * e(x)
  - ax * e(y)

= ( ay, -ax )
Tuloksena vektori on kohtisuorassa yhden panoksen vektoria.
Jos x-y plane on tarkasteltava siten, että x korotukset on rightward suuntaan ja y nousu ylöspäin suuntaan, sitten rajat tuote Tuloksena on neljäsosa-käännös "myötäpäivään" suhteessa tuotantopanoksista vektoria.
Esimerkkejä eri tuotteiden kaksiulotteisessa avaruudessa:
Cross( e(x) ) = (-1) * e(y)
Cross( e(y) ) =        e(x)
For kolmiulotteisuus, ja vektorit A = ( ax, ay, az ) ja B = ( bx, by, bz ):
Cross( A, B )

= Determinant
    (
        e(x),    e(y),    e(z),
         ax,      ay,      az,
         bx,      by,      bz
    )

=   (ay*bz - az*by) * e(x)
  + (az*bx - ax*bz) * e(y)
  + (ax*by - ay*bx) * e(z)

= ( (ay*bz - az*by), (az*bx - ax*bz), (ax*by - ay*bx) )
Esimerkkejä eri tuotteiden kolmiulotteisuus:
Cross( e(x), e(y) ) =        e(z)
Cross( e(y), e(x) ) = (-1) * e(z)

Cross( e(y), e(z) ) =        e(x)
Cross( e(z), e(y) ) = (-1) * e(x)

Cross( e(z), e(x) ) =        e(y)
Cross( e(x), e(z) ) = (-1) * e(y)
Neljän-ulotteinen avaruus, ja vektorit A = ( ax, ay, az, aw ), B = ( bx, by, bz, bw ), ja C = ( cx, cy, cz, cw ):
Cross( A, B, C )

= Determinant
  (
        e(x),    e(y),    e(z),    e(w),
         ax,      ay,      az,      aw,
         bx,      by,      bz,      bw,
         cx,      cy,      cz,      cw
  )

=   ( ay*bz*cw - ay*bw*cz + az*bw*cy - az*by*cw + aw*by*cz - aw*bz*cy) * e(x)
  + (-ax*bz*cw + ax*bw*cz - az*bw*cx + az*bx*cw - aw*bx*cz + aw*bz*cx) * e(y)
  + ( ax*by*cw - ax*bw*cy + ay*bw*cx - ay*bx*cw + aw*bx*cy - aw*by*cx) * e(z)
  + (-ax*by*cz + ax*bz*cy - ay*bz*cx + ay*bx*cz - az*bx*cy + az*by*cx) * e(w)

= ( ( ay*bz*cw - ay*bw*cz + az*bw*cy - az*by*cw + aw*by*cz - aw*bz*cy),
    (-ax*bz*cw + ax*bw*cz - az*bw*cx + az*bx*cw - aw*bx*cz + aw*bz*cx),
    ( ax*by*cw - ax*bw*cy + ay*bw*cx - ay*bx*cw + aw*bx*cy - aw*by*cx),
    (-ax*by*cz + ax*bz*cy - ay*bz*cx + ay*bx*cz - az*bx*cy + az*by*cx)  )
Esimerkkejä eri tuotteiden neljän-ulotteinen avaruus:
Cross( e(x), e(y), e(z) ) = (-1) * e(w)
Cross( e(x), e(z), e(y) ) =        e(w)
Cross( e(y), e(x), e(z) ) =        e(w)
Cross( e(y), e(z), e(x) ) = (-1) * e(w)
Cross( e(z), e(x), e(y) ) = (-1) * e(w)
Cross( e(z), e(y), e(x) ) =        e(w)

Cross( e(x), e(y), e(w) ) =        e(z)
Cross( e(x), e(w), e(y) ) = (-1) * e(z)
Cross( e(y), e(x), e(w) ) = (-1) * e(z)
Cross( e(y), e(w), e(x) ) =        e(z)
Cross( e(w), e(x), e(y) ) =        e(z)
Cross( e(w), e(y), e(x) ) = (-1) * e(z)

Cross( e(x), e(z), e(w) ) = (-1) * e(y)
Cross( e(x), e(w), e(z) ) =        e(y)
Cross( e(z), e(x), e(w) ) =        e(y)
Cross( e(z), e(w), e(x) ) = (-1) * e(y)
Cross( e(w), e(x), e(z) ) = (-1) * e(y)
Cross( e(w), e(z), e(x) ) =        e(y)

Cross( e(y), e(z), e(w) ) =        e(x)
Cross( e(y), e(w), e(z) ) = (-1) * e(x)
Cross( e(z), e(y), e(w) ) = (-1) * e(x)
Cross( e(z), e(w), e(y) ) =        e(x)
Cross( e(w), e(y), e(z) ) =        e(x)
Cross( e(w), e(z), e(y) ) = (-1) * e(x)
Alla oleva koodi pakottavaa rajat tuotteen kahden tai useamman vektorit.
Testi esimerkit osoittavat, että ei-nolla tulos vektorit ovat kohtisuorassa kaikkia tuotantopanoksista vektorit.
public class MatrixF64
{
    // . . .




    public static VectorF64 Cross( params VectorF64[] parameterArray )
    {
        if (null == parameterArray)
        {
            return(new VectorF64());
        }

        int totalVectors = parameterArray.Length;

        // The number of dimensions of the space must be one larger
        // than the number of specified vectors.
        int dimensions = (1 + totalVectors);

        if (dimensions < 2)
        {
            // The cross product does not exist for space with
            // fewer than two dimensions.
            return (new VectorF64());
        }

        // All specified vectors must exist and must have a number
        // of components equal to the number of dimensions of the space.
        for (int k = 0; k < totalVectors; k++)
        {
            if (null == parameterArray[k])
            {
                // Vector missing.
                return (new VectorF64());
            }
            else if (null == parameterArray[k].components)
            {
                // Vector is empty.
                return (new VectorF64());
            }
            else if (parameterArray[k].components.Length != dimensions)
            {
                // Vector has the wrong number of components.
                return (new VectorF64());
            }
        }

        // Form a (d*d) matrix with the (d-1) supplied vectors
        // forming the final (d-1) rows of the matrix.
        MatrixF64 matrix = MatrixF64.Zero( dimensions, dimensions );

        for (int i = 1; i < dimensions; i++)
        {
            VectorF64 rowVector = parameterArray[ i - 1 ];
            for (int j = 0; j < dimensions; j++)
            {
                matrix[i, j] = rowVector[j];
            }
        }

        VectorF64 result = VectorF64.Zero( dimensions );

        // For each component of the result vector, set the first
        // row of the matrix to a basis vector, compute the matrix
        // determinant, and use the resulting value as the
        // component of the result vector.  This is inefficient,
        // due to the determinant being computed (d) times.
        // Clearly it would be better to have explicit formulas
        // for 2-dimensional, 3-dimensional, and 4-dimensional
        // cross-products.
        for (int i = 0; i < dimensions; i++)
        {
            // Set the first row of the matrix to be the basis
            // vector for the coordinate axis with index (i).
            for (int j = 0; j < dimensions; j++)
            {
                matrix[0, j] = 0.0;
            }
            matrix[0, i] = 1.0;

            // Compute the determinant of the modified matrix.
            double determinant = matrix.Determinant();

            // Set component (i) of the result to the determinant
            // that was computed.
            result[i] = determinant;
        }

        return (result);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Examples of cross products:

        // Three-dimensional example:

        VectorF64 vcp1x3a = new VectorF641.02.03.0 );
        VectorF64 vcp1x3b = new VectorF643.01.02.0 );

        VectorF64 vcp1x3 = VectorF64.Cross( vcp1x3a, vcp1x3b );
        vcp1x3.WriteLine(); // (  1,  7, -5 )

        // Verify that the result is perpendicular to the original
        // vectors:
        Log.WriteLine( VectorF64.Perpendicular( vcp1x3, vcp1x3a ) );
        Log.WriteLine( VectorF64.Perpendicular( vcp1x3, vcp1x3b ) );
        // True, True

        // Four-dimensional example:

        VectorF64 vcp1x4a = new VectorF641.02.03.04.0 );
        VectorF64 vcp1x4b = new VectorF644.01.02.03.0 );
        VectorF64 vcp1x4c = new VectorF643.04.01.02.0 );

        VectorF64 vcp1x4 = VectorF64.Cross( vcp1x4a, vcp1x4b, vcp1x4c );
        vcp1x4.WriteLine(); // (   4,   4,  44, -36 )

        // Verify that the result is perpendicular to the original
        // vectors:
        Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4a ) );
        Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4b ) );
        Log.WriteLine( VectorF64.Perpendicular( vcp1x4, vcp1x4c ) );
        // True, True, True


        // . . .
    }
}

3.18 Matrix: inverse

"matrix inverse:" A square matrix etuyhteydessä toiseen neliö matriisin saman kokoinen sellainen, että tuote kaksi matriisit on "identiteetti matriisi."
Jos matriisi on liitetty inverse matrix, on olemassa vain yksi tällainen inverse matrix.
Jos tekijä matriisi on nolla, niin matriisi on nimetty "yksikkö," ja matriisi ei ole assosioitunut inverse matrix.
Alla oleva koodi pakottavaa käänteistä mitään square, ei-yksikkö matriisi.
Käänteisesti: 1*1, 2*2, 3*3, ja 4*4 matriisit ovat computed nimenomaisella kaavoja.
Käyttämällä selkeitä kaavoja voisi olla nopeampi kuin käyttäen yleistä menettelyä.
Nimenomaista kaavoja ovat myös luotettavia.
Menettely yleisen tapauksessa käyttää LU factoring, mutta on olemassa monia muita menetelmiä computing käänteisesti, matriisit.
public class MatrixF64
{
    // . . .




    private MatrixF64 Inverse1x1()
    {
        if
        (
               (this.totalRows != 1)
            || (this.totalColumns != 1)
            || (null == this.entries)
        )
        {
            return (MatrixF64.Zero( 11 )); // Matrix is empty.
        }

        if (0.0 == this[0,0])
        {
            return ( MatrixF64.Zero( 11 ) ); // Matrix has no inverse.
        }

        MatrixF64 inverse = MatrixF64.Zero( 11 );

        // The inverse of a 1x1 matrix is simply the
        // reciprocal of the single entry.
        inverse[0,0] = (1.0 / this[0,0]);

        return (inverse);
    }




    private MatrixF64 Inverse2x2()
    {
        if
        (
               (this.totalRows != 2)
            || (this.totalColumns != 2)
            || (null == this.entries)
        )
        {
            return (MatrixF64.Zero( 22 )); // Matrix is empty.
        }

        double determinant = this.Determinant2x2();
        if (0.0 == determinant)
        {
            return (MatrixF64.Zero( 22 )); // Matrix has no inverse.
        }

        MatrixF64 inverse = MatrixF64.Zero( 22 );


        inverse[0,0] = this[1,1];
        inverse[0,1] = (-(this[0,1]));
        inverse[1,0] = (-(this[1,0]));
        inverse[1,1] = this[0,0];


        double factor = (1.0 / determinant);
        for ( int i = 0; i < inverse.totalRows; i++ )
        {
            for ( int j = 0; j < inverse.totalColumns; j++ )
            {
                inverse[i,j] *= factor;
            }
        }

        return (inverse);
    }




    private MatrixF64 Inverse3x3()
    {
        if
        (
               (this.totalRows != 3)
            || (this.totalColumns != 3)
            || (null == this.entries)
        )
        {
            return (MatrixF64.Zero( 33 )); // Matrix is empty.
        }

        double determinant = this.Determinant3x3();
        if (0.0 == determinant)
        {
            return (MatrixF64.Zero( 33 )); // Matrix has no inverse.
        }

        MatrixF64 inverse = MatrixF64.Zero( 33 );


        inverse[00] =
              this[11] * this[22]
            - this[12] * this[21];
        inverse[01] =
              this[02] * this[21]
            - this[01] * this[22];
        inverse[02] =
              this[01] * this[12]
            - this[02] * this[11];

        inverse[10] =
              this[12] * this[20]
            - this[10] * this[22];
        inverse[11] =
              this[00] * this[22]
            - this[02] * this[20];
        inverse[12] =
              this[02] * this[10]
            - this[00] * this[12];

        inverse[20] =
              this[10] * this[21]
            - this[11] * this[20];
        inverse[21] =
              this[01] * this[20]
            - this[00] * this[21];
        inverse[22] =
              this[00] * this[11]
            - this[01] * this[10];


        double factor = (1.0 / determinant);
        for (int i = 0; i < inverse.totalRows; i++)
        {
            for (int j = 0; j < inverse.totalColumns; j++)
            {
                inverse[i, j] *= factor;
            }
        }

        return (inverse);
    }




    private MatrixF64 Inverse4x4()
    {
        if
        (
               (this.totalRows != 4)
            || (this.totalColumns != 4)
            || (null == this.entries)
        )
        {
            return (MatrixF64.Zero( 44 )); // Matrix is empty.
        }

        double determinant = this.Determinant4x4();
        if (0.0 == determinant)
        {
            return (MatrixF64.Zero( 44 )); // Matrix has no inverse.
        }

        MatrixF64 inverse = MatrixF64.Zero( 44 );


        inverse[0,0] =
        + this[1,1] * this[2,2] * this[3,3]
        + this[1,2] * this[2,3] * this[3,1]
        + this[1,3] * this[2,1] * this[3,2]
        - this[1,1] * this[2,3] * this[3,2]
        - this[1,2] * this[2,1] * this[3,3]
        - this[1,3] * this[2,2] * this[3,1];

        inverse[0,1] =
        + this[0,1] * this[2,3] * this[3,2]
        + this[0,2] * this[2,1] * this[3,3]
        + this[0,3] * this[2,2] * this[3,1]
        - this[0,1] * this[2,2] * this[3,3]
        - this[0,2] * this[2,3] * this[3,1]
        - this[0,3] * this[2,1] * this[3,2];

        inverse[0,2] =
        + this[0,1] * this[1,2] * this[3,3]
        + this[0,2] * this[1,3] * this[3,1]
        + this[0,3] * this[1,1] * this[3,2]
        - this[0,1] * this[1,3] * this[3,2]
        - this[0,2] * this[1,1] * this[3,3]
        - this[0,3] * this[1,2] * this[3,1];

        inverse[0,3] =
        + this[0,1] * this[1,3] * this[2,2]
        + this[0,2] * this[1,1] * this[2,3]
        + this[0,3] * this[1,2] * this[2,1]
        - this[0,1] * this[1,2] * this[2,3]
        - this[0,2] * this[1,3] * this[2,1]
        - this[0,3] * this[1,1] * this[2,2];


        inverse[1,0] =
        + this[1,0] * this[2,3] * this[3,2]
        + this[1,2] * this[2,0] * this[3,3]
        + this[1,3] * this[2,2] * this[3,0]
        - this[1,0] * this[2,2] * this[3,3]
        - this[1,2] * this[2,3] * this[3,0]
        - this[1,3] * this[2,0] * this[3,2];

        inverse[1,1] =
        + this[0,0] * this[2,2] * this[3,3]
        + this[0,2] * this[2,3] * this[3,0]
        + this[0,3] * this[2,0] * this[3,2]
        - this[0,0] * this[2,3] * this[3,2]
        - this[0,2] * this[2,0] * this[3,3]
        - this[0,3] * this[2,2] * this[3,0];

        inverse[1,2] =
        + this[0,0] * this[1,3] * this[3,2]
        + this[0,2] * this[1,0] * this[3,3]
        + this[0,3] * this[1,2] * this[3,0]
        - this[0,0] * this[1,2] * this[3,3]
        - this[0,2] * this[1,3] * this[3,0]
        - this[0,3] * this[1,0] * this[3,2];

        inverse[1,3] =
        + this[0,0] * this[1,2] * this[2,3]
        + this[0,2] * this[1,3] * this[2,0]
        + this[0,3] * this[1,0] * this[2,2]
        - this[0,0] * this[1,3] * this[2,2]
        - this[0,2] * this[1,0] * this[2,3]
        - this[0,3] * this[1,2] * this[2,0];


        inverse[2,0] =
        + this[1,0] * this[2,1] * this[3,3]
        + this[1,1] * this[2,3] * this[3,0]
        + this[1,3] * this[2,0] * this[3,1]
        - this[1,0] * this[2,3] * this[3,1]
        - this[1,1] * this[2,0] * this[3,3]
        - this[1,3] * this[2,1] * this[3,0];

        inverse[2,1] =
        + this[0,0] * this[2,3] * this[3,1]
        + this[0,1] * this[2,0] * this[3,3]
        + this[0,3] * this[2,1] * this[3,0]
        - this[0,0] * this[2,1] * this[3,3]
        - this[0,1] * this[2,3] * this[3,0]
        - this[0,3] * this[2,0] * this[3,1];

        inverse[2,2] =
        + this[0,0] * this[1,1] * this[3,3]
        + this[0,1] * this[1,3] * this[3,0]
        + this[0,3] * this[1,0] * this[3,1]
        - this[0,0] * this[1,3] * this[3,1]
        - this[0,1] * this[1,0] * this[3,3]
        - this[0,3] * this[1,1] * this[3,0];

        inverse[2,3] =
        + this[0,0] * this[1,3] * this[2,1]
        + this[0,1] * this[1,0] * this[2,3]
        + this[0,3] * this[1,1] * this[2,0]
        - this[0,0] * this[1,1] * this[2,3]
        - this[0,1] * this[1,3] * this[2,0]
        - this[0,3] * this[1,0] * this[2,1];


        inverse[3,0] =
        + this[1,0] * this[2,2] * this[3,1]
        + this[1,1] * this[2,0] * this[3,2]
        + this[1,2] * this[2,1] * this[3,0]
        - this[1,0] * this[2,1] * this[3,2]
        - this[1,1] * this[2,2] * this[3,0]
        - this[1,2] * this[2,0] * this[3,1];

        inverse[3,1] =
        + this[0,0] * this[2,1] * this[3,2]
        + this[0,1] * this[2,2] * this[3,0]
        + this[0,2] * this[2,0] * this[3,1]
        - this[0,0] * this[2,2] * this[3,1]
        - this[0,1] * this[2,0] * this[3,2]
        - this[0,2] * this[2,1] * this[3,0];

        inverse[3,2] =
        + this[0,0] * this[1,2] * this[3,1]
        + this[0,1] * this[1,0] * this[3,2]
        + this[0,2] * this[1,1] * this[3,0]
        - this[0,0] * this[1,1] * this[3,2]
        - this[0,1] * this[1,2] * this[3,0]
        - this[0,2] * this[1,0] * this[3,1];

        inverse[3,3] =
        + this[0,0] * this[1,1] * this[2,2]
        + this[0,1] * this[1,2] * this[2,0]
        + this[0,2] * this[1,0] * this[2,1]
        - this[0,0] * this[1,2] * this[2,1]
        - this[0,1] * this[1,0] * this[2,2]
        - this[0,2] * this[1,1] * this[2,0];


        double factor = (1.0 / determinant);
        for (int i = 0; i < inverse.totalRows; i++)
        {
            for (int j = 0; j < inverse.totalColumns; j++)
            {
                inverse[i, j] *= factor;
            }
        }

        return (inverse);
    }




    public MatrixF64 Inverse()
    {
        if
        (
               (this.totalRows <= 0)
            || (this.totalColumns <= 0)
            || (null == this.entries)
        )
        {
            return (MatrixF64.Zero( 11 )); // Matrix is empty.
        }

        if (this.totalRows != this.totalColumns)
        {
            // Matrix is not square
            return (MatrixF64.Zero( 11 ));
        }

        // Simple cases
        if (1 == this.totalRows) { return (this.Inverse1x1()); }
        if (2 == this.totalRows) { return (this.Inverse2x2()); }
        if (3 == this.totalRows) { return (this.Inverse3x3()); }
        if (4 == this.totalRows) { return (this.Inverse4x4()); }


        int[] rowPermutationOfOriginalMatrix = null;
        bool rowExchangeParityIsOdd = false;
        MatrixF64 originalMatrix = new MatrixF64this );
        MatrixF64 LUFactorsMatrix = null;

        MatrixF64.FindLUFactorsOfARowPermutedVersionOfAnOriginalMatrix
            (
            originalMatrix,
            ref LUFactorsMatrix,
            ref rowPermutationOfOriginalMatrix,
            ref rowExchangeParityIsOdd
            );

        if ((null == LUFactorsMatrix)
            || (null == rowPermutationOfOriginalMatrix))
        {
            return (MatrixF64.Zero( this.totalRows, this.totalColumns ));
        }


        VectorF64 columnVector = VectorF64.Zero( totalRows );
        VectorF64 solutionVector = VectorF64.Zero( totalRows );
        MatrixF64 inverse =
            MatrixF64.Zero( this.totalRows, this.totalColumns );
        for (int j = 0; j < inverse.totalColumns; j++)
        {
            for (int i = 0; i < inverse.totalRows; i++)
            {
                columnVector[i] = 0.0;
            }
            columnVector[j] = 1.0;

            MatrixF64.LUBacksubstitution
                (
                LUFactorsMatrix,
                rowPermutationOfOriginalMatrix,
                columnVector,
                ref solutionVector
                );
            if (null != solutionVector)
            {
                for (int i = 0; i < inverse.totalRows; i++)
                {
                    inverse[i, j] = solutionVector[i];
                }
            }
        }

        return (inverse);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Examples of matrix inverses:

        MatrixF64 m2x2 =
            new MatrixF64
            (
            22,
             2.05.0// row 0
            -4.0-7.0  // row 1
            );
        MatrixF64 inversem2x2 = m2x2.Inverse();
        inversem2x2.WriteLine();
        // [  -1.1666667, -0.83333333 ]
        // [  0.66666667,  0.33333333 ]

        MatrixF64 prodinvm2x2andm2x2 = inversem2x2 * m2x2;
        prodinvm2x2andm2x2.WriteLine();
        // [             1, 8.8817842e-16 ]
        // [             0,             1 ]
        // This product is very close to a
        // 2x2 identity matrix, as it should be.

        MatrixF64 prodm2x2andinvm2x2 = m2x2 * inversem2x2;
        prodm2x2andinvm2x2.WriteLine();
        // [ 1, 0 ]
        // [ 0, 1 ]
        // This product is the 2x2 identity matrix,
        // as it should be.


        MatrixF64 m3x3 =
            new MatrixF64
            (
            33,
             2.0,  5.07.0// row 0
            -4.0-1.06.0// row 1
             9.0,  8.03.0  // row 2
            );
        MatrixF64 inversem3x3 = m3x3.Inverse();
        inversem3x3.WriteLine();
        // [ -0.76119403,   0.6119403,  0.55223881 ]
        // [  0.98507463, -0.85074627, -0.59701493 ]
        // [ -0.34328358,  0.43283582,  0.26865672 ]

        MatrixF64 prodinvm3x3andm3x3 = inversem3x3 * m3x3;
        prodinvm3x3andm3x3.WriteLine();
        // [             1,             0, 4.4408921e-16 ]
        // [             0,             1,             0 ]
        // [             0,             0,             1 ]
        // This product is very close to a 3x3 identity matrix,
        // as it should be.

        MatrixF64 prodm3x3andinvm3x3 = m3x3 * inversem3x3;
        prodm3x3andinvm3x3.WriteLine();
        // [              1, -4.4408921e-16,  4.4408921e-16 ]
        // [              0,              1,  -2.220446e-16 ]
        // [ -4.4408921e-16,              0,              1 ]
        // This product is very close to a 3x3 identity matrix,
        // as it should be.


        // . . .
    }
}

3.19 Multiplicative tuote matriisi ja vektori

The multiplicative tuote matriisi (M) ja vektorin (a) on vektori (b); (M)*(a) = (b).
Matrix (M) "muuntaa" vektorin (a), vektori (b).
Alla oleva koodi pakottavaa että multiplicative tuote matriisi ja vektori.
public class MatrixF64
{
    // . . .




    public static VectorF64 operator *( MatrixF64 m, VectorF64 v )
    {
        if (null == m)
        {
            return (null); // Matrix is not specified.
        }

        if
        (
               (null == m.entries)
            || (m.totalRows <= 0)
            || (m.totalColumns <= 0)
        )
        {
            return (null); // Matrix is empty.
        }

        if (null == v)
        {
            // Vector is not specified.
            return (VectorF64.Zero( m.totalRows ));
        }

        if (v.Dimensions() != m.totalColumns)
        {
            // The number of columns of the matrix must be equal
            // to the number of rows of the vector.
            return (VectorF64.Zero( m.totalRows ));
        }


        // The result vector has the same number of rows as the matrix.
        VectorF64 result = VectorF64.Zero( m.totalRows );


        // Component (i) of the result vector is equal to the
        // dot product of row (i) of the matrix with the vector.
        for (int i = 0; i < m.totalRows; i++)
        {
            double dotProduct = 0.0;
            for (int j = 0; j < m.totalColumns; j++)
            {
                dotProduct += (m[i, j] * v[j]);
            }
            result[i] = dotProduct;
        }

        return (result);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Examples of a product of a matrix and a vector:

        MatrixF64 t3x3 =
            new MatrixF64
            (
            33,
             2.05.07.0// row 0
            -4.0-1.06.0// row 1
             9.08.03.0  // row 2
            );

        VectorF64 p3x1 = new VectorF641.02.03.0 );

        VectorF64 q3x1 = t3x3 * p3x1;
        q3x1.WriteLine();
        // ( 33, 12, 34 )


        // The multiplicative product of the inverse
        // of the matrix and the result vector computed
        // above should reproduce the original vector.
        MatrixF64 inverset3x3 = t3x3.Inverse();

        VectorF64 prodinvt3x3andq3x1 = inverset3x3 * q3x1;
        prodinvt3x3andq3x1.WriteLine();
        // ( 1, 2, 3 )
        // This vector is equal to the original vector,
        // as expected.


        // . . .
    }
}

3.20 Using homogeeniset matriisit kääntää homogeeninen vektorit

"translation:" An toimintaa T(s), jotka on määritelty tietty vektorin (s), joka muuntaa minkä tahansa vektorin (r) on vastaava vektori (r + s); T(s) * (r) = (r + s).
T(-s) on käänteinen T(s); Inverse(T(s)) = T(-s); T(-s) * (r) = (r - s).
A käännös toiminta voi edustaa matriisi siten, että kertomalla käännös matriisi, jonka vektori on vaikutusta kääntämiseen, että vektori.
Aineistossa on käännös operaation osien tulos vektorin eivät riippuvat, suoraan tai välillisesti, osien alkuperäistä vektoria.
Näin ollen käännös matriisi on jäsennetty tavalla, jonka ansiosta se voi vaikuttaa käännös on tulos ilman, että vaikuttaa suoraan tai välillisesti sen osien alkuperäistä vektoria.
"Homogeeninen vektori" on vektorin kanssa lopullista komponenttia yhtä 1.
"Homogeeninen matriisi" on matriisi, jonka lopullinen rivi kanssa kaikki merkinnät yhtä 0 lukuun ottamatta lopullista tuloa 1.
The multiplicative tuote on homogeeninen matriisi ja toinen homogeeninen matriisi on homogeeninen matriisi.
The multiplicative tuote on homogeeninen matriisi ja homogeeninen vektori on homogeeninen vektoria.
Yksi mielenkiintoinen määrite tämän tuotteen, on se, että merkinnät Viimeiseen sarakkeeseen on homogeeninen matriisi, lukuun ottamatta lopullinen merkintä, on lisätty suoraan komponenttien tulos vektorin ilman, että vaikuttaa suoraan tai välillisesti sen osien alkuperäinen vektori.
Näin ollen käännös toimintaa voidaan asiamiehet homogeeninen matriisi, ja tällainen matriisi voidaan kääntää homogeeninen vektorit.
Jos haluamme edustavat kannat ja suunnassa, (d)-ulotteinen avaruus, ja me haluamme käyttää matriiseja kääntää kantoja, niin homogeeninen matriisit ja homogeeninen vektorit voidaan käyttää.
Kuitenkin homogeeninen vektorit on (d+1) komponentteja, ja homogeeninen matriisit on ((d+1)*(d+1)) merkinnät.
Viimeinen osa homogeeninen vektori ja lopullinen rivi homogeeninen matriisi eivät vastaa mitään niistä (d) koordinaatit että haluamme edustaa (d)-ulotteinen avaruus, mutta sen sijaan vain on mahdollista saada matriisit tehdä tiettyjä toimia, jotka riippumatta siitä (d) koordinoida arvoja.
Using homogeeniset matriisit ja homogeeninen vektorit helpottaa yhdiste muutoksia ja hakea muutoksia vektorihyönteisiin, mutta muiden toimintojen entistä epämukavaa.
Edustaminen kantoja tai suunnassa, (d)-ulotteinen avaruus käyttäen homogeeninen vektorit tarkoittaa, että vektorit on (d+1) komponentteja, joiden lopullista komponenttia yhtä 1.
Computing piste tuotteen kahden homogeeninen vektoreita käyttämällä säännöllisesti piste-tuote toimintoa voitaisiin yhdistää implisiittisesti piste tuote ensimmäisen (d) komponentteja, joilla on merkitystä arvo 1 vuoksi lopullinen osien 1.
Näin ollen saada piste tuote asiaa (d) komponentit, homogeeninen vektorin ((d+1) komponentit), piste tuote homogeeninen vektorit olisi tehtävä käyttäen erityistä "homogeeninen vektori-piste tuote-toiminto," yksinkertaisesti kelaa lopullinen osa vektoreita.
Vaihtoehtoisesti, piste tuote voi olla yhtiön kanssa säännöllisesti piste tuote-toimintoa ymmärtämistä, että määrä 1 olisi vähennettävä tulos ennen tulkinnassa tuloksen, jotka koskevat (d) asiaa koordinaatit.
Alla oleva koodi näyttää, miten matriisi voidaan muodostaa, että voidaan sitten käyttää kääntämään vektoria.
public class MatrixF64
{
    // . . .




    public static MatrixF64 FormHomogeneousTranslationMatrix( VectorF64 v )
    {
        // This method assumes the specified vector is a homogeneous
        // vector, where the final component is not relevant to the
        // translation.  Thus, we form a square homogeneous matrix
        // with a total number of rows equal to the number of
        // components of the specified vector.  We form an identity
        // matrix of the required size, and copy all but the final
        // component of the specified vector to the final column of
        // the matrix.
        if (null == v)
        {
            return (MatrixF64.Zero( 11 )); // Vector is not specified.
        }

        if (v.Dimensions() <= 0)
        {
            return (MatrixF64.Zero( 11 )); // Vector is empty.
        }

        MatrixF64 result =
            MatrixF64.Identity( v.Dimensions() );

        // Add all but the final component of the specified vector
        // to the final column of the result matrix.  The final
        // entry of the final column of the matrix will remain one (1).
        for (int i = 0; i < (result.totalRows - 1); i++)
        {
            result[i, (result.totalColumns - 1)] = v[i];
        }

        return (result);
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of using a homogeneous matrix to
        // translate a homogeneous vector:

        // Forming a homogeneous matrix that represents
        // a translation:

        VectorF64 homogeneousTranslationVector4x1 =
            new VectorF6410.020.030.01.0 );

        MatrixF64 translation4x4 =
            MatrixF64.FormHomogeneousTranslationMatrix
                ( homogeneousTranslationVector4x1  );

        translation4x4.WriteLine();
        // [  1,  0,  0, 10 ]
        // [  0,  1,  0, 20 ]
        // [  0,  0,  1, 30 ]
        // [  0,  0,  0,  1 ]


        // Using the homogeneous matrix to translate
        // a homogeneous vector:

        VectorF64 homogeneousVector =
            new VectorF645.06.07.01.0 );

        VectorF64 translatedVector =
            translation4x4 * homogeneousVector;

        translatedVector.WriteLine();
        // ( 15, 26, 37,  1 )
        // The relevant vector components (5,6,7)
        // were translated by (10,20,30) by the
        // homogeneous translation matrix.


        // . . .
    }
}

3.21 (d)-ulotteinen avaruus: kierrosten

"kierto (d)-ulotteinen avaruus:" Toimeen (R) määritetty kaksi-ulotteinen kierto plane (S), pyörimissuunnan kulma (t), ja kierto Center Point (c), joka muuntaa mitä tahansa kohtaa (p) on vastaava kohta (q) siten, että:
(1) Length( q - c ) = Length( p - c ); välinen etäisyys uusi kohta ja kierto Center Point on sama kuin etäisyys alkuperäisen pisteen ja kierto Center Point.
Näin ollen uusi kohta on pinnalla erityisesti (d)-ulotteinen pallo;
(2) Let (P) oltava lentokoneessa, joka on yhdensuuntainen kierto plane (S) ja sisältää kohta (p).
Kohta (q) tulee plane (P).
Näin ollen uusi kohta on tietyssä kaksiulotteinen plane vuonna (d)-ulotteinen avaruus;
(3) Dot( (q - c), (p - c) ) = Length( q - c ) * Length( p - c ) * Cos( t ); piste tuote vektorin osoitteesta vuorojärjestelmän Center Point, että alkuperäinen piste ja vektori-vuorojärjestelmän Center Point, että uusi piste on yhtä kuin tuote, pituudet näiden kahden vektorit ja cosine, vuoroviljely kulma.
Näin ollen uusi kohta on pinnalla erityisesti (d)-ulotteinen tähkistä;
Constraint (1) rajoitetaan uusi kohta sen pinnalla erityisesti (d)-ulotteinen pallo.
Edellytys (2) edelleen rajoittaa uusi kohta, joka erityisesti kaksiulotteinen plane vuonna (d)-ulotteinen avaruus.
Näin ollen uusi kohta on tietyssä kaksiulotteinen ympyrä, (d)-ulotteinen avaruus.
Edellytys (3) edelleen rajoittaa uusi kohta, joka erityisesti (d)-ulotteinen käpy.
Näin ollen uusi kohta on yksi erityisesti kohta (Cos( t ) = 1 tai Cos( t ) = (-1)) tai yksi kaksi mahdollista pistettä ((-1) < Cos( t ) < 1).
Yksi lopullinen rajoitus on tarpeen valita toinen kahdesta mahdollisesta kohtia, jotka johtuvat rajoitukset mainittiin edellä.
Let T(s) edustaa "käännös" operaatioon, jossa (s) on mielivaltainen vektori siten, että T(s) * (r) = (r + s), ja Inverse(T(s)) * (r) = (r - s).
Vuorottelua R(S,t,c), plane S, kulma t, ja Center Point c, voidaan ilmaista Kääntämisen operaatioita ja vuorottelua, jonka keskitaajuus pisteen alkuperä: R(S,t,c) = T(c) * R(S,t,0) * T(-c) = T(c) * R(S,t,0) * Inverse(T(c)).
Let R(S,t) edustaa kiertävä toimintaa, jossa pyörimisliike center pisteen alkuperä (d)-ulotteinen avaruus.
Näin ollen kaikki mielivaltainen kierto voidaan ilmaista seuraavasti: R(S,t,c) = T(c) * R(S,t) * T(-c) = T(c) * R(S,t) * Inverse(T(c)).
Pohtikaamme kaksiulotteinen kierto lentokoneita (S), jotka sisältävät alkuperän (d)-ulotteinen avaruus ja ovat rinnakkain kaksi koordinoida akseleilla.
Let (a) ja (b) olla kokonaislukuja, jotka edustavat koordinoida akselit, (d)-ulotteinen avaruus, sellainen, että 0 <= a <= (d-1), ja 0 <= b <= (d-1), ja (a != b).
Voimme määritellä R(a,b,t) on kiertävä noin alkuperän (d)-ulotteinen avaruus, kiertävä plane parallel koordinoida akselit merkitään koordinoida indeksit (a) ja (b), ja kulmassa (t) siten, että R(a,b,(pi/2)) olisi muuntaa myönteinen koordinoida arvo on koordinoida akselilla ilmoitetaan (a) on myönteinen koordinoida arvo on koordinoida akselilla ilmoitetaan (b); esimerkki: R(a,b,(pi/2)) * e(a) = e(b), jossa e(k) osoittaa yksikön perusteella vektorin vastaava koordinoida akselilla (k).
Tämä määritelmä antaa lopullinen disambiguation tarpeen täysin määrittää uusi kohta, jota tuottavat kiertoa.
Vuorottelua, joka liikkuu pistettä pitkin akselilla a suuntaan akselilla b mukaan kulmassa t vastaa kiertävä, joka liikkuu pistettä pitkin akselilla b suuntaan akselilla a jonka kulma (-t); eli R(a,b,t) = R(b,a,(-t)).
Jos (d >= 2), sitten (d)-ulotteinen avaruus on ((d*(d-1))/2) paria koordinoida akseleilla.
Näin ollen (d >= 2), (d)-ulotteinen avaruus on ((d*(d-1))/2) erilliset akselilla liittoutumaton kierto lentokoneita.
(Esimerkkejä: d=2: (x-y plane); d=3: (x-y plane, y-z plane, z-x plane); d=4: (x-y plane, y-z plane, z-x plane, x-w plane, z-w plane, w-y plane).)
Alla oleva koodi näyttää, miten matriisi voidaan käyttää edustamaan kierto R(a,b,t).
Yksi esimerkki on osoittanut, että käyttää kiertoa matriksi homogeeninen tavalla pyörittää homogeeninen vektorin uuteen homogeeninen vektoria.
public class MatrixF64
{
    // . . .




    public static MatrixF64 Rab( int rows, int a, int b, double angle )
    {
        if (rows <= 0)
        {
            // Invalid row count specified.
            return (MatrixF64.Zero( 11 ));
        }

        MatrixF64 result = MatrixF64.Identity( rows );

        // If (a==b) (rotate coordinate (a) to (a)), then
        // there is no rotation to do.

        if ((a != b) && (a >= 0) && (a < rows) && (b >= 0) && (b < rows))
        {
            double sine = Math.Sin( angle );
            double cosine = Math.Cos( angle );

            // Override m[a,a] = cosine;  m[a,b] = -sine;
            //          m[b,a] =   sine;  m[b,b] = cosine;
            result[a, a] = cosine;
            result[b, b] = cosine;
            result[a, b] = (-(sine));
            result[b, a] = sine;
        }

        return (result);
    }




    public static MatrixF64 Rabk( int rows, int a, int b, int k )
    {
        double angle = (Math.PI / 2.0) * (double)k;
        return (MatrixF64.Rab( rows, a, b, angle ));
    }




    // . . .




    public static void Test()
    {
        // . . .


        // Example of using a homogeneous matrix
        // to rotate a homogeneous vector:

        // Forming a homogeneous rotation matrix that
        // rotates a positive component along coordinate
        // axis 0 to a positive component along
        // cooridnate axis 1, in 3-dimensional space.
        // (The homogeneous matrix must be (3+1)=4
        // rows by (3+1)=4 columns.)

        MatrixF64 rotation4x4 =
            MatrixF64.Rab( 401, (0.5 * Math.PI) );

        rotation4x4.WriteLine(3);
        // [ 6.12e-17,       -1,        0,        0 ]
        // [        1, 6.12e-17,        0,        0 ]
        // [        0,        0,        1,        0 ]
        // [        0,        0,        0,        1 ]
        // (The entries '6.12e-17' are negligible.)
        // The upper-left 3x3 part of the matrix represents
        // a counterclockwise rotation of a quarter-turn
        // such that a positive component along axis 0
        // would be rotated to a positive component along
        // axis 1, in 3-dimensional space.

        // Using the homogeneous rotation matrix to
        // rotate a homogeneous vector:

        VectorF64 homogeneousVector2 =
            new VectorF645.06.07.01.0 );

        VectorF64 rotatedVector =
            rotation4x4 * homogeneousVector2;

        rotatedVector.WriteLine();
        // ( -6,  5,  7,  1 )
        // The relevant vector components (5,6,7) were
        // rotated to (-6,5,7), which is consistent with
        // a counterclockwise quarter-turn rotation
        // with a rotation plane parallel to axes 0 and 1.


        // . . .
    }
}

3.22 Ehdotettu määritelmä "vastapäivään"

Vuonna kaksiulotteinen avaruus, neljäsosa-käännös kierto, joka voi muuntaa vektorin e(0), e(1) katsotaan vastapäivään.
Vuorojärjestelmän on: R(0,1,(pi/2)) * e(0) = e(1).
Tästä syystä kiertoajan R(0,1,t) on vastapäivään.
Vuonna kolmiulotteisuus, neljäsosa-käännös kierto, joka voi muuntaa vektorin e(0), e(1) katsotaan vastapäivään.
Vuosineljänneksen puolestaan kierto, joka voi muuntaa vektorin e(1), e(2) on myös katsottava vastapäivään.
Vuosineljänneksen puolestaan kierto, joka voi muuntaa vektorin e(2), e(0) on myös katsottava vastapäivään.
Näin ollen kierrosten { R(0,1,t), R(1,2,t), R(2,0,t) } ovat vastapäivään.
The Boolen kaava alle sopii määritelmä vastapäivään kaksi-ulotteinen ja kolmiulotteisuus ja extrapolates kaava yleisen tapauksessa kiertoajan R(a,b,t):
bool counterClockwise =
(
       ( (a < b) && (((a + b) % 2) == 1) )
    || ( (a > b) && (((a + b) % 2) == 0) )
);
Tämä sääntö olisi määriteltävä kierrosten jäljempänä "vastapäivään:"
R(0,1,t),
R(2,0,t), R(1,2,t),
R(0,3,t), R(3,1,t), R(2,3,t),
R(4,0,t), R(1,4,t), R(4,2,t), R(3,4,t),
R(0,5,t), R(5,1,t), R(2,5,t), R(5,3,t), R(4,5,t),
...

3.23 (d)-ulotteinen avaruus: myötäpäivään kierrosten

Using ehdotettu määritelmä "vastapäivään," edellisessä jaksossa, kierrosten alla ovat "myötäpäivään:"
R(1,0,t),
R(0,2,t), R(2,1,t),
R(3,0,t), R(1,3,t), R(3,2,t),
R(0,4,t), R(4,1,t), R(2,4,t), R(4,3,t),
R(5,0,t), R(1,5,t), R(5,2,t), R(3,5,t), R(5,4,t),
...
Esimerkiksi neljän-ulotteinen avaruus, kuuden kierto matriisit Jäljempänä myötäpäivään kierrosten:
R(1,0,t) =     Cos(t),  Sin(t),    0,       0,
              -Sin(t),  Cos(t),    0,       0,
                 0,       0,       1,       0,
                 0,       0,       0,       1


R(0,2,t) =     Cos(t),    0,    -Sin(t),    0,
                 0,       1,       0,       0,
               Sin(t),    0,     Cos(t),    0,
                 0,       0,       0,       1


R(2,1,t) =       1,       0,       0,       0,
                 0,     Cos(t),  Sin(t),    0,
                 0,    -Sin(t),  Cos(t),    0,
                 0,       0,       0,       1


R(3,0,t) =     Cos(t),    0,       0,     Sin(t),
                 0,       1,       0,       0,
                 0,       0,       1,       0,
              -Sin(t),    0,       0,     Cos(t)


R(1,3,t) =       1,       0,       0,       0,
                 0,     Cos(t),    0,    -Sin(t),
                 0,       0,       1,       0,
                 0,     Sin(t),    0,     Cos(t)


R(3,2,t) =       1,       0,       0,       0,
                 0,       1,       0,       0,
                 0,       0,     Cos(t),  Sin(t),
                 0,       0,    -Sin(t),  Cos(t)

3.24 (d)-ulotteinen avaruus: kokonaismäärästä akselilla liittoutumaton suuntaviivat

The useita eri akselilla liittoutumaton linjausten (d)-ulotteinen avaruus on:
distinctOrientations = Factorial( d ) * IntPow( 2, (d-1) );
Yksi argumentti tukee tätä kaavaa näkyy kohdat alla.
Kokeellinen näyttö tarkastamaan kaava on myös esitetty alla.
Let { g(0), g(1), ..., g(d-1) } on joukko (d) toisiaan kohtisuorassa yksikkö vektorit liitteenä esineen (d)-ulotteinen avaruus.
Nämä yksikön vektorit osoittavat, että suunta objektin suhteellinen on koordinoida akselit, (d)-ulotteinen avaruus.
Let the "default suunta" tavoitteena oltava sellainen, että g(i) = e(i), kaikki 0 <= i <= (d-1); kunkin suuntautumisen vektori, tavoitteena on liitetty erillinen yksikkö perusteella vektori, joka koordinoi järjestelmän kanssa (d)-ulotteinen avaruus.
Ensimmäinen suuntautumiseen vektori, tavoitteena voi olla samanaikaisesti jonkin (d) akselit, (d)-ulotteinen avaruus, ja se voi olla joko molempiin suuntiin suhteessa, että akselilla.
Näin ollen ensimmäisen suuntautumiseen vektori on (2 * d) vaihtoehtoja.
Toinen suuntautumiseen vektori, tavoitteena voi olla rinnakkaista johonkin (d-1) jäljellä olevat akselit, joissa on kaksi mahdollista suuntiin suhteessa, että akselilla.
Näin ollen toinen suuntautumiseen vektori on (2 * (d-1)) vaihtoehtoja.
Vuonna samalla tavalla, seuraava suuntautumiseen vektori on (2 * (d-2)) vaihtoehtoja.
Viimeinen suuntautumiseen vektori on pakko lopullinen jäljellä akselilla, ja on pakko yksi niistä kaksi mahdollista suuntiin pitkin, että akseli (säilyttämistä koskevaa yhdenmukaista joukoksi suuntautumiseen vektorit, tekijä, joka määräsi joukko suuntasi vektorit on oltava vakio ).
Näin ollen lopullinen suuntautumiseen vektori on vain (1) vaihtoehto.
Kokonaismäärä yhdistelmiä on antanut tuotetta: ((2 * d) * (2 * (d-1)) * ...  * (2 * 3) * (2 * 2) * (1)) = (2^(d-1)) * (d*(d-1)*(d-2)*...*2*1) = (2^(d-1)) * Factorial(d).
Kohdan alle nykyisen rauhoittavaa kokeellista näyttöä tueksi kaava kokonaismäärästä akselilla liittoutumaton linjausta, jossa tavoitteena voi olla.
Ohjauskurssin objektin voi edustaa matriisi (M) jossa vektorit { g(0), g(1), ..., g(d-1) } ovat sarakkeissa matriisi: