пятница, 1 июля 2011 г.

Мой первый проект на GitHub

Давно хотел создать какой-нибудь общедоступный проект, ну и начал с самого мне необходимого – математической библиотеки, доступной здесь. Сейчас в ней только один класс, обеспечивающий работу с матрицами – теми самыми, что Вы могли встретить в курсе высшей математики в институте.
Для создания объекта-матрицы вызываем конструктор, который создает нулевую матрицу (т.е. матрицу, у которой все элементы равны нулю):
var newMatrix:MatrixMath = new MatrixMath(numRows, numCols);
где numRows – число строк, а numCols – число столбцов матрицы.
Для заполнения коэффициентов матрицы случайными числами вызываем следующий метод:
newMatrix.random(min, max);
где min и max – границы диапазона случайных чисел, которые будут заполнять матрицу.
Для задания значения конкретного элемента матрицы используйте метод:
newMatrix.setElement(row, col, value);
где row – номер строки, col – номер столбца (внимание, row и col отсчитываются от нуля), value – задаваемое значение элемента.
Есть также пара методов для задания значений всех элементов матрицы из массивов:
setMatrixFromRows(rowsVector:Vector.<Vector.<Number>>) – как видно, в качестве аргумента принимает двумерный массив элементов (число строк и столбцов матрицы рассчитывается исходя из размеров данного массива);
setMatrixFromVector(matrixVector:Vector.<Number>, numRows:uint, numCols:uint) – в качестве аргумента принимает одномерный массив, а также число строк и столбцов матрицы.
Для чтения значений элементов матрицы есть метод
getElement(row:uint, col:uint)
Основным применением данного класса является решение систем линейных уравнений. В моей реализации данного класса эту задачу можно выполнить тремя способами:
1) это решение уравнений с помощью метода Крамера. Данный метод решения наиболее ресурсоемкий и использовать его для систем более, чем с 8 неизвестными – крайне не рекомендуется (программа «повиснет»). Был реализован чисто «из спортивного интереса». Пример использования:
// Создаем матрицу, состоящую из коэффициентов при неизвестных 
// и заполняем ее случайными значениями
var testMatr1:MatrixMath = new MatrixMath(3, 3);
testMatr1.random(0, 100);
trace("A:");
// Трассируем содержимое матрицы
testMatr1.traceMatrix();
// Создаем матрицу, состоящую из свободных членов уравнений
var testMatr2:MatrixMath = new MatrixMath(3, 1);
testMatr2.random(0, 50);
trace("B:");
testMatr2.traceMatrix();
trace("Cramer Solution:");
// Создаем матрицу-столбец, содержащую решение системы уравнений
var testMatr:MatrixMath = MatrixMath.CramerSolution(testMatr1, testMatr2);
// Выводим на экран ее содержимое
trace(testMatr.m);

2) решение системы с помощью метода Гаусса:
var testMatr1:MatrixMath = new MatrixMath(3, 3);
testMatr1.random(0, 100);
trace("A:");
testMatr1.traceMatrix();
var testMatr2:MatrixMath = new MatrixMath(3, 1);
testMatr2.random(0, 50);
trace("B:");
testMatr2.traceMatrix();
trace("Gauss Solution");
// Создаем матрицу-столбец, содержащую решение системы уравнений
testMatr = MatrixMath.GaussSolution(testMatr1, testMatr2);
trace(testMatr.m);

Видим, что решение системы уравнений в первом и втором случае отличается всего лишь одной строкой, в чем же разница? Она заключается в точности вычислений. Метод Крамера очень медленный, но дает более точные результаты, т.к. при нахождении значений неизвестных в нем осуществляется лишь одна операция деления. Но метод Гаусса гораздо-гораздо быстрее и дает ответ, отличающийся лишь на миллионные доли, что является приемлемым.

3) Решение с помощью LUP-разложения позволяет быстро решать множество систем уравнений, отличающихся лишь значениями свободных членов. Данный способ отличается от метода Гаусса тем, что позволяет «запоминать» последовательность операций, необходимых для решения системы уравнений. Пример использования:
trace("LUP Solution");
var testMatr1:MatrixMath = new MatrixMath(3, 3);
testMatr1.random(0, 100);
trace("A:");
testMatr1.traceMatrix();
// Создаем т.н. матрицу перестановок, в которой хранится 
// информация о необходимых действиях
var permutationMatr:MatrixMath = new MatrixMath(testMatr1.rows, 1);
// Внимание, метод LUPDecomposition изменяет значения элементов 
// в матрицах testMatr1 и permutationMatr, поэтому, 
// если Вам необходимо сохранить исходные значения 
// элементов матриц, то используйте метод clone:
var cloneMatr:MatrixMath = testMatr1.clone();
// Выполняем необходимые преобразования матриц
MatrixMath.LUPDecomposition(cloneMatr, permutationMatr);
// Создаем матрицу, состоящую из свободных членов уравнений
var testMatr2:MatrixMath = new MatrixMath(3, 1);
testMatr2.random(0, 50);
trace("B:");
testMatr2.traceMatrix();
// Создаем матрицу-столбец, содержащую решение системы уравнений
testMatr = MatrixMath.LUPSolution(cloneMatr, testMatr1, testMatr2);
// Выводим на экран решение
trace(testMatr.m);
// Давайте теперь решим другую систему уравнений, 
// отличающуюся только значениями свободных членов
// Зададим новые значения свободных членов уравнений:
testMatr2.random(0, 100);
// Снова решаем систему уравнений, 
// используя уже преобразованные матрицы
testMatr = MatrixMath.LUPSolution(cloneMatr, testMatr1, testMatr2);
trace(testMatr.m);

Кроме методов для решения систем уравнений в данном классе реализован функционал по основным операциям над матрицами: сложение, вычитание, умножение матриц, умножение матрицы на число, транспонирование, нахождение обратной матрицы, вычисление определителя (двумя способами: с помощью метода Гаусса и с помощью рекурсии. Второй метод гораздо медленнее и более ресурсоемкий, но немного точнее), а также другие вспомогательные методы.
Названия методов в классе говорят сами за себя, плюс в коде есть комментарии (приношу извинения за свой корявый английский в них).

На сегодня – все. Надеюсь, что следующая статья будет посвящена продолжению темы векторов :)

Комментариев нет:

Отправить комментарий