PDA

View Full Version : Matricies



poltomb
02-09-2007, 09:10 PM
Well, I hadn't seen anything like this made yet so I went on and attempted it.

I have made a Matrix class (no, not the movie). It allows for the matrix math in uscript.

I just need some testing. I hope this will be useful for someone.


////////////////////////////////////////////////////////////////////////////
// Matrix class will allow you do create your own matricies and
// perform the most common operations on them.
//
// Note: The matricies may be zero-indexed (first row = 0 and first column = 0)
// or one-indexed (first row = 1, first column = 1),
// depending on your preference.
//
// Created by HTM~Parlatz
////////////////////////////////////////////////////////////////////////////

class Matrix extends Object;

var int m; // Number of rows.
var int n; // Number of columns.
var bool zeroIndexed; // If true, the first row and first column of a matrix are labeled as '0'. Defaults to true.
var array<float> matrixValues; // Actual values of the matrix.


// Creates zero-filled matrix.
simulated function createMatrix(int rows, int columns, bool zIndex)
{
local int i;

m = rows;
n = columns;
zeroIndexed = zIndex;
matrixValues.length = rows * columns;

for (i=0; i<matrixValues.length; i++)
{
matrixValues[i] = 0;
}
}

// Sets a single element in the matrix.
simulated function bool setValue(int rowNum, int colNum, float value)
{
local int arrayPosition;

if (!zeroIndexed)
{
rowNum -= 1;
colNum -= 1;
}

arrayPosition = rowNum * colNum + colNum;

matrixValues[arrayPosition] = value;

return true;
}

// Set an entire row of the matrix by using an array of values
// which has a length = n (number of columns).
simulated function bool setRow(int rowNum, array<float> values)
{
local int arrayPosition;
local int i;

if (!zeroIndexed)
rowNum -= 1;

if (values.length != n)
return false;

for (i=0; i<values.length; i++)
{
arrayPosition = rowNum * n + i;
matrixValues[arrayPosition] = values[i];
}

return true;
}

// Set an entire column of the matrix by using an array of values
// which has a length = m (number of rows).
//
// This may be useful when doing matrix-vector calculations.
// (If you don't know what this means, then don't worry. Just ignore it.)
simulated function bool setColumn(int colNum, array<float> values)
{
local int arrayPosition;
local int i;

if (!zeroIndexed)
colNum -= 1;

if (values.length != m)
return false;

for (i=0; i<values.length; i++)
{
arrayPosition = i * m + colNum;
matrixValues[arrayPosition] = values[i];
}

return true;
}

// Returns the value at the row and column specified.
simulated function float getValue(int rowNum, int colNum)
{
local int arrayPosition;

if (!zeroIndexed)
{
rowNum -= 1;
colNum -= 1;
}

arrayPosition = rowNum * colNum + colNum;

return matrixValues[arrayPosition];
}

// Returns an array of values corresponding to the row specified.
simulated function array<float> getRow(int rowNum)
{
local int arrayPosition;
local int i;
local array<float> values;

if (!zeroIndexed)
rowNum -= 1;

values.length = n;

for (i=0; i<n; i++)
{
arrayPosition = rowNum * n + i;
values[i] = matrixValues[arrayPosition];
}

return values;
}

// Returns an array of values corresponding to the column specified.
//
// This may be useful when doing matrix-vector calcualtions.
// (Again, if you don't know what this means, then don't worry. Just ignore it.)
simulated function array<float> getColumn(int colNum)
{
local int arrayPosition;
local int i;
local array<float> values;

if (!zeroIndexed)
colNum -= 1;

values.length = m;

for (i=0; i<m; i++)
{
arrayPosition = i * m + colNum;
values[i] = matrixValues[arrayPosition];
}

return values;
}

// A helper funtion used by 'multiply' to make for easier reading.
private static final function float arrayMultiply(array<float> A, array<float> B)
{
local int i;
local float total;

total = 0;

for (i=0; i<A.length; i++)
{
total += A[i]*B[i];
}

return total;
}

// Multiply two matricies together, if the columns of A match the rows of B and return the resultant matrix.
static final function Matrix matrixMultiply(Matrix A, Matrix B)
{
local Matrix C;
local int i, j;

if (A.n != B.m)
return None;

C = new class'Matrix';
C.createMatrix(A.m, B.n, A.zeroIndexed);

for (i=0; i<C.m; i++)
{
for (j=0; j<C.n; j++)
{
C.setValue(i, j, arrayMultiply(A.getRow(i), B.getColumn(j)));
}
}

return C;
}

// Scale the given matrix by the factor given.
static final function Matrix matrixScale(float factor, Matrix A)
{
local int i;
local Matrix B;

B = new class'Matrix';

B.createMatrix(A.m, A.n, A.zeroIndexed);

for (i=0; i<A.matrixValues.length; i++)
{
B.matrixValues[i] = A.matrixValues[i] * factor;
}

return B;
}

// Add two matricies together.
static final function Matrix matrixAdd(Matrix A, Matrix B)
{
local int i;
local Matrix C;

if (A.m != B.m || A.n != B.n)
return None;

C = new class'Matrix';

C.createMatrix(A.m, A.n, A.zeroIndexed);

for (i=0; i<A.matrixValues.Length; i++)
{
C.matrixValues[i] = A.matrixValues[i] + B.matrixValues[i];
}

return C;
}

// Subtract the first matrix from the second matrix.
static final function Matrix matrixSubtract(Matrix A, Matrix B)
{
return class'Matrix'.static.matrixAdd(A, matrixScale(-1, b));
}

// Transposing a matrix causes its dimensions to reverse (ie 3x2 -> 2x3).
//
// | 1 2 | | 1 3 5 |
// | 3 4 | ---> | 2 4 6 |
// | 5 6 |
//
static final function Matrix transpose(Matrix A)
{
local Matrix B;
local int i;

B = new class'Matrix';

B.createMatrix(A.n, A.m, A.zeroIndexed);

for (i=0; i<A.m; i++)
B.setRow(i, A.getColumn(i));

return B;
}

// Returns a matrix containing the sums of each row's elements. Row numbers correlate.
static final function Matrix rowSum(Matrix A)
{
local Matrix B;
local int i;

B = new class'Matrix';
B.createMatrix(A.n, 1, A.zeroIndexed);
for (i=0; i<B.m; i++)
B.matrixValues[i] = 1;

return class'Matrix'.static.matrixMultiply(A, B);
}

// Returns a matrix containing the sums of each column's elements. Column numbers correlate.
static final function Matrix columnSum(Matrix A)
{
local Matrix B;
local int i;

B = new class'Matrix';
B.createMatrix(1, A.m, A.zeroIndexed);
for (i=0; i<B.n; i++)
B.matrixValues[i] = 1;

return class'Matrix'.static.matrixMultiply(B, A);
}

// The next three private functions are helper functions for gaussian elimination,
// and are not needed elsewhere outside the class.
private static final function swapRows(out Matrix A, int rowA, int rowB)
{
local array<float> tempFloatArray;

tempFloatArray = A.getRow(rowA);
A.setRow(rowA, A.getRow(rowB));
A.setRow(rowB, tempFloatArray);
}

private static final function divideRow(out Matrix A, int rowNum, float divisor)
{
local array<float> tempRow;
local int i;

tempRow = A.getRow(rowNum);

for (i=0; i<tempRow.length;i++)
tempRow[i] /= divisor;

A.setRow(rowNum, tempRow);
}

private static final function subtractRow(out Matrix A, int rowA, int rowB, float factor)
{
local array<float> tempA, tempB;
local int i;

tempA = A.getRow(rowA);
tempB = A.getRow(rowB);

for (i=0; i<tempA.length; i++)
tempA[i] *= factor;

for (i=0; i<tempA.length; i++)
tempB[i] -= tempA[i];

A.setRow(rowB, tempB);
}

// This method (function) performs Gaussian Elimination on a matrix. It puts the matrix into echelon form.
// For more information on Gaussian Elimination or matricies in general,
// see: http://mathworld.wolfram.com/GaussianElimination.html
// Method was based on the pseudocode algorithm provided by Wikipedia
// at: http://en.wikipedia.org/wiki/Gaussian_elimination
static final function Matrix gaussianElimination(Matrix A)
{
local int i, j, k, u;
local float maxValue, value;
local int maxValueIndex;

i = 0;
j = 0;

while (i<A.m && j<A.n)
{
maxValue = A.getValue(i, j);
maxValueIndex = i;
for (k=i+1; k<A.m; k++)
{
value = A.getValue(k, j);
if (Abs(value) > Abs(maxValue))
{
maxValue = value;
maxValueIndex = k;
}
}

if (maxValue != 0)
{
class'Matrix'.static.swapRows(A, i, maxValueIndex);
class'Matrix'.static.divideRow(A, i, MaxValue);

for (u=i+1; u<A.m; u++)
{
class'Matrix'.static.subtractRow(A, i, u, A.getValue(u,j));
}

i++;
}

j++;
}

return A;
}

// This function returns the reduced-row echelon form of a matrix.
static final function Matrix gaussJordanElimination(Matrix A)
{
local int i, j, p, u;

A = class'Matrix'.static.gaussianElimination(A);

i = A.m - 1;
j = A.n - 1;

for (i=i; i>=0; i--)
{
for (p=0; p<=j; p++)
{
if (A.getValue(i, p) != 0)
{
for (u=i; u>=0; u--)
class'Matrix'.static.subtractRow(A, i, u, A.getValue(u, p));
}

break;
}
}

return A;
}

defaultproperties
{
}

poltomb
02-10-2007, 04:46 AM
Just tested on my own, after reading about commandlets.

Known Bugs:

--Entire Class

I think I need to look at the code after a bit. If anyone has suggestions on fixes, let me know.

Lotus
02-11-2007, 05:12 AM
There already exists a struct called 'matrix' in object. So, you might run into problems there.

Wormbo
02-12-2007, 04:34 AM
The matrix struct is a fixed-size 3x3 matrix and IIRC there are no operators of functions for it. As far as I can see, this class allows any size for the matrix.

I have to admit, though, that I don't know what you would need a matrix for in UnrealScript...

Jrubzjeknf
02-12-2007, 07:26 AM
Some time ago I was thinking about perhaps making a Binary Tree datatype. Didn't do it, because there is *no* use for it, unfortunately.

poltomb
02-12-2007, 10:38 AM
its proving much more difficult than i planned...damn uscript and its lack of 2d arrays.

Also, the algorithms are proving more difficult to translate into uscript

Wormbo
02-12-2007, 02:36 PM
I have a rudimentary BigInt implementation for UnrealScript somewhere on my HD, but didn't continue it becasue there's no point in doing so.