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

1. Software

LinearAlgebra.zip
Linear algebra source code (C#)
19910 bytes
MD5: 11d8c8035cac30ba543e5e0b72ee9767

2. Introduction

This article describes vectors and matrices in (d)-dimensional space.

3. (d)-dimensional space : attributes

3.1 Array

"array" : A collection of variables such that each variable has a unique name, and such that the names can be assigned an order.
Integer values can be used as names for the variables in an array.
For example, if an array contains (d) variables, then the integer values { 0, 1, 2, ..., (d-1) } can be the names assigned to the variables in the array.

3.2 (d)-dimensional vector

"(d)-dimensional vector" : An array of (d) variables.
"vector component" : A variable within a vector.

3.3 (d)-dimensional vector space

"one-dimensional space" : The complete set of values that can be stored by one variable.
"(d)-dimensional space" : The complete set of combinations of values that can be stored by an array of (d) variables.
The formal definition of a "vector space":
Let (T) be a basic type (examples: real number, integer, complex number, rational number, etc).
Any variable of a basic type is named a "scalar".
A "(T)-type (d)-dimensional vector space" is the set (S) of (d)-dimensional vectors having two operations, vector addition (+), and scalar multiplication (*), satisfying the conditions below:
(1) If (v) and (w) are any two vectors in (S), then (v + w) is also a vector in (S);
(2) If (u), (v), and (w) are any three vectors in (S), then (u + v) + w = u + (v + w);
[additive commutativity]
(3) If (v) and (w) are any two vectors in (S), then (v + w) = (w + v);
[additive associativity]
(4) There is a "zero vector", (0), in (S), such that for any vector (v) in (S), (v + (0)) = v;
[additive identity]
(5) If (c) is any scalar of type (T), and (v) is any vector in (S), then the product (c * v) is a vector in (S);
(6) If (a), (b), and (c) are any scalars of type (T), and (v) and (w) are any vectors in (S), then (a + b) * v = a*v + b*v, and c*(v + w) = c*v + c*w;
[multiplicative distributivity]
(7) If (a) and (b) are any scalars of type (T), and (v) is any vector in (S), then (a*b)*v = a*(b*v);
(8) If "1" is a scalar of type (T) such that (1*1)=1, and (v) is any vector in (S), then (1*v) = v;
(9) For each vector (v) in (S), the vector (-1)*v = -v satisfies v + (-v) = (0);
[additive inverse]

3.4 (d)-dimensional vector code

The code below shows how a (d)-dimensional vector, with 64-bit floating-point components, can be implemented.
An array is sufficient to represent a vector.
The code below has an array contained in a class, only for convenience.
The code is not intended to be efficient.
A structure (example: "struct", a value type) representing vectors of a fixed number of dimensions (examples: 3 or 4) is likely to be much more efficient than the general (d)-dimensional vector class shown here.
Although the code below defines a vector with floating-point components, this document also makes use of vectors with integer components.
The code below can easily be modified to implement vectors with integer components.
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)-dimensional zero vector" : A vector with all (d) components equal to zero.
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)-dimensional space : points

"(d)-dimensional space point" : An array of (d) variables with specific values ("coordinate values").
"(d)-dimensional space origin" : An array of (d) variables with all values equal to zero.

3.6 (d)-dimensional vectors : non-relative and relative

A (d)-dimensional vector that is "non-relative" is a (d)-dimensional vector that directly represents a status or configuration.
A (d)-dimensional vector that is "relative" is a (d)-dimensional vector that represents changes to a set of components.
A relative vector can represent the difference between two non-relative vectors.
Given a relative vector, determining a non-relative status or configuration using that relative vector requires combining that relative vector with a non-relative vector.
Non-relative vectors and relative vectors are both vectors.
Whether a particular vector is non-relative or relative must be specified when the vector is defined.
If a (d)-dimensional vector is interpreted as being non-relative, then the (d)-dimensional vector can represent a point in (d)-dimensional space.

3.7 (d)-dimensional vector addition, subtraction, and scaling

Vector addition, subtraction, and scaling:
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)-dimensional basis vectors

The formal definition of a "basis" of a vector space:
Let (T) be a basic type (examples: real number, integer, complex number, rational number, etc).
Any variable of a basic type is named a "scalar".
Let (V) be a "(T)-type (d)-dimensional vector space".
If the non-zero vectors { u1, u2, ..., ud } in (V) are such that every vector (v) in (V) can be written as a "linear combination" of those vectors, v = c1*u1 + c2*u2 + ... + cd*ud, where { c1, c2, ..., cd } are scalars of type (T), then (V) is "spanned" by vectors { u1, u2, ..., ud }.
Any set of non-zero vectors { u1, u2, ..., ud } that "span" vector space (V) is named a "basis" of (V).
One simple "basis" of a (d)-dimensional vector space is the set of (d) distinct (d)-dimensional vectors, each with one component equal to one and all other components equal to zero.
Such basis vectors are "orthonormal", meaning that they are mutually-perpendicular ("orthogonal") and that each vector has unit length.
Each such vector is a unit vector parallel to one of the (d) coordinate axes.
Expressing an arbitrary vector as a "linear combination" of these basis vectors is direct; each component of the arbitrary vector is multiplied by the corresponding basis vector, and these products are added together to form the arbitrary vector.
The code below shows how a vector can be expressed as a "linear combination" of basis vectors.
The code below arbitrarily defines an orthonormal set of basis vectors.
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 )


        // . . .
    }
}
Any vector in (d)-dimensional space can be expressed as a sum of the products of numbers and basis vectors:
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)-dimensional space : distance between points

Let (P) be a (d)-dimensional vector that represents a point in (d)-dimensional space.
Let (Q) be a (d)-dimensional vector that represents a point in (d)-dimensional space.
Let (R) be a (d)-dimensional vector that represents the change in (d) coordinates to get from point (P) to point (Q); R = (Q - P).
In one-dimensional space, P = ( p0 ), Q = ( q0 ), and R = (Q - P) = ( q0 - p0 ).
The distance between the two points is: Abs( q0 - p0 ).
In two-dimensional space, P = ( p0, p1 ), Q = ( q0, q1 ), and R = (Q - P) = ( q0-p0, q1-p1 ).
Interpreting the two perpendicular displacements as the perpendicular sides of a right-triangle, the distance between the points corresponds to the length of the hypotenuse of that triangle.
The Pythagorean formula, (a*a) + (b*b) = (c*c), where (a) and (b) are the lengths of the perpendicular sides of a right-triangle, and (c) is the length of the hypotenuse (skew side), can be used to determine the distance between the two points: Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
In three-dimensional space, P = ( p0, p1, p2 ), Q = ( q0, q1, q2 ), and R = (Q - P) = ( q0-p0, q1-p1, q2-p2 ).
Interpreting the displacement ( q0-p0, q1-p1, 0 ) as the perpendicular sides of a right-triangle, and using the Pythagorean formula, gives the distance between point (P) and the point ( q0, q1, p2 ): d01 = Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
The displacement ( q0-p0, q1-p1, 0 ) is perpendicular to the displacement ( 0, 0, q2-p2 ), and another right-triangle can be formed, and the Pythagorean formula can be used again.
Thus, the distance from point (P) to point (Q) is given by: 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) ).
The method of extending the distance formula from two-dimensional space to three-dimensional space can be applied repeatedly to eventually determine the distance formula for (d)-dimensional space: Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) + ... + Sq(qd-pd) ).
The code below defines a function named "Length" which computes the length of a (d)-dimensional vector.
When a vector represents the displacement between two points in (d)-dimensional space, the length of the vector represents the distance between those two points.
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)-dimensional vectors : dot product

The "dot product" converts two (d)-dimensional vectors to a number.
The code below computes a dot product of two vectors:
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);
    }




    // . . .
}
For any vector, (A), Length(A) = Sqrt(Dot(A,A)).

3.11 (d)-dimensional vectors : definition of "parallel"

Vectors (A) and (B) are "parallel" if all of the following are true:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = A.Length()*B.Length().
The code below determines if a pair of vectors are parallel (possibly anti-aligned).
Floating-point numbers can accumulate errors in the fractional part due to the limited precision, and, therefore, computer code should include non-zero tolerances when comparing floating-point numbers.
The code includes example tolerance values, but the example tolerance values might not be appropriate for some tasks.
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)-dimensional vectors : definition of "perpendicular"

Vectors (A) and (B) are "perpendicular" if all of the following are true:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = 0.
The code below determines if a pair of vectors are perpendicular. Floating-point numbers can accumulate errors in the fractional part due to the limited precision, and, therefore, computer code should include non-zero tolerances when comparing floating-point numbers.
The code includes example tolerance values, but the example tolerance values might not be appropriate for some tasks.
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

"matrix" : A collection of variables such that each variable has a unique combination of a "row" name and a "column" name.
"entry" : A variable within a matrix.
Integer values can be used as "row" names and "column" names for the variables in a matrix.
For example, if a matrix has (totalRows) rows and (totalColumns) columns, then the integer values { 0, 1, ..., (totalRows-1) } can be the names assigned to the rows, and the integer values { 0, 1, ..., (totalColumns-1) } can be the names assigned to the columns.
Thus, a variables in a matrix can be specified by specifying a pair of integers, ( row, column ), indicating the combination of row and column indices corresponding to the specific variable.
The size of a matrix is specified as "(totalRows) * (totalColumns)" (or "(totalRows) by (totalColumns)").
This order of dimensions is the same as the order of dimensions used to specify entries in the matrix ("( row, column )").
[ This convention is somewhat unfortunate, because for many two-dimensional uses (examples: images, graphs, etc) the usual convention is to specify dimensions as "width * height" and coordinates as "( horizontal, vertical )" (or "( x, y )").
This is the opposite of the order of dimensions and coordinates used to describe matrices and their entries. ]
A matrix with (totalRows) equal to (totalColumns) is named "square"; otherwise, the matrix is named "rectangular".
A matrix can be regarded as containing a set of "row vectors", where the variables in each row are interpreted as belonging to a vector.
A matrix can also be regarded as containing a set of "column vectors", where the variables in each column are interpreted as belonging to a vector.
Matrices can represent a wide variety of mathematical relationships.
The meaning of a matrix, and the operations that might be appropriate for processing entries of a matrix, depends on the context.
However, there are basic rules of matrix arithmetic that are relevant to many contexts, and these basic rules will be defined in a subsequent section.
An array and a (totalColumns) value are sufficient to represent a matrix.
The array can have (totalRows * totalColumns) variables, and the entry at ( row, column ) can correspond to the array variable at index ((totalColumns * row) + column).
The code below defines a matrix, with 64-bit floating-point entries.
An array and a (totalColumns) value are sufficient to represent a matrix.
The code below has an array and a (totalColumns) value contained in a class, only for convenience.
The code below is not intended to be efficient.
A structure (example: "struct", a value type) representing matrices of particular fixed dimensions (examples: 2*2, 3*3, or 4*4) is likely to be much more efficient than the general (totalRows * totalColumns) class shown here.
Although the code below defines a matrix with floating-point entries, this article also makes use of matrices with integer entries.
The code below can be easily modified to implement matrices with integer entries.
using System;
using System.Collections.Generic;
using System.Text;

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

publi