From 0fc76027c1fbc87a64bc9aa075638640ae4b5116 Mon Sep 17 00:00:00 2001 From: Pohlod Slavik Date: Tue, 23 Oct 2012 21:54:20 +0300 Subject: [PATCH] Hi all. I like to use yours matnet numeric library, few days ago I write interesting Knuth algorithm for work with sparse matrixes. Ill fix it. PS: Sorry for my bad english, I just learn it) --- .../LinearAlgebra/Double/KnuthNode.cs | 132 +++++ .../LinearAlgebra/Double/KnuthSparseMatrix.cs | 453 ++++++++++++++++++ src/Numerics/Numerics.csproj | 2 + 3 files changed, 587 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Double/KnuthNode.cs create mode 100644 src/Numerics/LinearAlgebra/Double/KnuthSparseMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Double/KnuthNode.cs b/src/Numerics/LinearAlgebra/Double/KnuthNode.cs new file mode 100644 index 00000000..7304c409 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/KnuthNode.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.LinearAlgebra.Double +{ + /// + /// Node to store elements in Knuth sparse matrix + /// + public class KnuthNode + { + /// + /// Row position of element + /// + public int Row + { + set; + get; + } + /// + /// Column possition of element + /// + public int Col + { + set; + get; + } + /// + /// Stored value + /// + public double Val + { + set; + get; + } + /// + /// Pointer to lefter element in row + /// + public KnuthNode Left + { + set; + get; + } + /// + /// pointer to upper element in column + /// + public KnuthNode Up + { + set; + get; + } + + /// + /// Initialize new default instanse of KnuthNode class + /// + public KnuthNode() + { + Row = -1; + Col = -1; + Val = 0; + Left = this; + Up = this; + } + /// + /// Initialize new instanse of KnuthNode class + /// + /// row number + /// column number + /// value + public KnuthNode(int x, int y, double val) + { + Row = x; + Col = y; + Val = val; + Left = this; + Up = this; + } + /// + /// Initialize new instanse of KnuthNode class + /// + /// row number + /// column number + /// value + /// pointer to lefter element in row + /// pointer to upper element in column + public KnuthNode(int x, int y, double val, KnuthNode left, KnuthNode up) + { + Row = x; + Col = y; + Val = val; + Left = left; + Up = up; + Left = this; + Up = this; + } + + /// + /// Check if elements are equal + /// + /// second element + /// if elements are equal + public bool Equals(KnuthNode nd2) + { + if (nd2 == null) + return false; + return Val == nd2.Val && Row == nd2.Row && Col == nd2.Col; + } + + /// + /// Oparetor of equality + /// + /// first element + /// second element + /// if elements are equals + public static bool operator ==(KnuthNode nd1, KnuthNode nd2) + { + return nd1.Equals(nd2); + } + + /// + /// Oparetor of equality + /// + /// first element + /// second element + /// if elements aren`t equals + public static bool operator !=(KnuthNode nd1, KnuthNode nd2) + { + return !(nd1 == nd2); + } + } +} diff --git a/src/Numerics/LinearAlgebra/Double/KnuthSparseMatrix.cs b/src/Numerics/LinearAlgebra/Double/KnuthSparseMatrix.cs new file mode 100644 index 00000000..947658df --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/KnuthSparseMatrix.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.LinearAlgebra.Double +{ + + /// + /// A Matrix class with sparse storage. The underlying storage scheme is pointers to lefter and upper elements Format. + /// Algorithm was posted in "The Art of Computer Programming" - Knuth - 1968 + /// + /// + class KnuthSparseMatrix + { + /// + /// list to begin rows elements + /// + private List Rows; + /// + /// list to begin cols elements + /// + private List Cols; + + /// + /// Gets the number of non zero elements in the matrix. + /// + /// The number of non zero elements. + public int NonZerosCount() + { + int result = 0; + for (int i = 0; i < Rows.Count; ++i) + { + KnuthNode iter = Rows[i]; + while (iter.Left != Rows[i]) + { + ++result; + iter = iter.Left; + } + } + return result; + } + + /// + /// Insert new value to current possition + /// + /// number of row + /// number of column + /// value to insert + private void Insert(int x, int y, double val) + { + if (val == 0) + { + Delete(x, y); + return; + } + KnuthNode rw = Rows[x]; + KnuthNode cl = Cols[y]; + KnuthNode toInsert = new KnuthNode(x, y, val); + //search needed row + while (rw.Left != Rows[x] && rw.Left.Col >= y) + { + rw = rw.Left; + } + //insert to row + if (rw.Col == y) // element allready exist + { + rw.Val = val; + } + else + { + toInsert.Left = rw.Left; + rw.Left = toInsert; + } + //search needed column + while (cl.Up != Cols[y] && cl.Up.Row >= x) + { + cl = cl.Up; + } + //insert to column + if (cl.Row == x) // element allready exist + { + cl.Val = val; + } + else + { + toInsert.Up = cl.Up; + cl.Up = toInsert; + } + } + /// + /// Delete current element + /// + /// number of row + /// number of column + private void Delete(int x, int y) + { + KnuthNode rw = Rows[x].Left, prewRw = Rows[x]; + KnuthNode cl = Cols[y].Up, prewCl = Cols[y]; + bool haver = false, havec = false; + for (int i = 0; i < Rows.Count; ++i) + { + if (rw.Col == y) + { + haver = true; + break; + } + prewRw = rw; + rw = rw.Left; + } + for (int i = 0; i < Cols.Count; ++i) + { + if (cl.Row == x) + { + havec = true; + break; + } + prewCl = cl; + cl = cl.Up; + } + if (havec && haver) + { + prewCl.Up = cl.Up; + prewRw.Left = rw.Left; + } + } + /// + /// Set bounds of new sparse matrix + /// + /// count of rows + /// count of cols + private void SetBounds(int row, int col) + { + Rows = new List(row); + for (int i = 0; i < row; ++i) + { + Rows.Add(new KnuthNode()); + } + Cols = new List(col); + for (int i = 0; i < col; ++i) + { + Cols.Add(new KnuthNode()); + } + } + /// + /// Create new instanse of sparse matrix + /// + /// number of rows + /// number of columns + public KnuthSparseMatrix(int row, int col) + { + SetBounds(row, col); + } + + /// + /// Create new instanse of sparse matrix + /// + /// matrix in standart presentation to set as sparse + public KnuthSparseMatrix(double[][] mtx) + { + SetBounds(mtx.Length, mtx[0].Length); + for (int i = 0; i < mtx.Length; ++i) + { + for (int j = 0; j < mtx[i].Length; ++j) + { + if (mtx[i][j] != 0) + { + Insert(i, j, mtx[i][j]); + } + } + } + } + + /// + /// Create new instanse of sparse matrix + /// + /// matrix in list presentation to set as sparse + public KnuthSparseMatrix(List> mtx) + { + SetBounds(mtx.Count, mtx[0].Count); + for (int i = 0; i < mtx.Count; ++i) + { + for (int j = 0; j < mtx[i].Count; ++j) + { + if (mtx[i][j] != 0) + { + Insert(i, j, mtx[i][j]); + } + } + } + } + + /// + /// Copy existing instanse of matrix to new matrix + /// + /// matrix to copy + public KnuthSparseMatrix(KnuthSparseMatrix mtx) + { + KnuthNode rw; + SetBounds(mtx.Rows.Count, mtx.Cols.Count); + for (int i = 0; i < Rows.Count; ++i) + { + rw = Rows[i].Left; + while (rw != Rows[i]) + { + Insert(rw.Row, rw.Col, rw.Val); + rw = rw.Left; + } + } + } + + /// + /// Change signs of all values to opposite + /// + public void Negate() + { + KnuthNode rw; + for (int i = 0; i < Rows.Count; ++i) + { + rw = Rows[i]; + while (rw.Left != Rows[i]) + { + rw.Val *= -1; + rw = rw.Left; + } + } + } + + /// + /// Multiply two sparse matrix + /// + /// first matrix + /// second matrix + /// result of multiplying this matrix + public static KnuthSparseMatrix operator *(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2) + { + if (mtx1.Cols.Count != mtx2.Rows.Count) + throw new Exception("Wrong size of matrix to multiple"); + KnuthSparseMatrix Res = new KnuthSparseMatrix(mtx1.Rows.Count, mtx2.Cols.Count); + double tmp; + KnuthNode Iter1, Iter2; + for (int i = 0; i < mtx1.Rows.Count; ++i) + { + for (int j = 0; j < mtx2.Cols.Count; ++j) + { + tmp = 0; //initalize mult of i-th row and j-th column + Iter1 = mtx1.Rows[i].Left; + Iter2 = mtx2.Cols[j].Up; + while (Iter1 != mtx1.Rows[i] && Iter2 != mtx2.Cols[j]) + { + if (Iter1.Col == Iter2.Row) + { + tmp += Iter1.Val * Iter2.Val; + Iter1 = Iter1.Left; + Iter2 = Iter2.Up; + } + else if (Iter1.Col < Iter2.Row) + { + Iter2 = Iter2.Up; + } + else //(Iter2.Col < Iter1.Col) + { + Iter1 = Iter1.Left; + } + } + if (tmp != 0) // paste not 0 element + { + Res.Insert(i, j, tmp); + } + + } + } + return Res; + } + + /// + /// Adds two matrixes + /// + /// first matrix + /// second matrix + /// result of summing this matrixes + public static KnuthSparseMatrix operator +(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2) + { + if (mtx1.Rows.Count != mtx2.Rows.Count || mtx1.Cols.Count != mtx2.Cols.Count) + throw new Exception("Wrong size of matrix to summ"); + KnuthSparseMatrix Res = new KnuthSparseMatrix(mtx1.Rows.Count, mtx1.Cols.Count); + KnuthNode Iter1, Iter2; + for (int i = 0; i < mtx1.Rows.Count; ++i) + { + Iter1 = mtx1.Rows[i].Left; + Iter2 = mtx2.Rows[i].Left; + while (Iter1 != mtx1.Rows[i] || Iter2 != mtx2.Rows[i]) + { + if (Iter1 == mtx1.Rows[i]) + { + Res.Insert(Iter2.Row, Iter2.Col, Iter2.Val); + Iter2 = Iter2.Left; + } + else if (Iter2 == mtx2.Rows[i]) + { + Res.Insert(Iter1.Row, Iter1.Col, Iter1.Val); + Iter1 = Iter1.Left; + } + else if (Iter1.Col == Iter2.Col) + { + Res.Insert(Iter1.Row, Iter1.Col, Iter1.Val + Iter2.Val); + Iter1 = Iter1.Left; + Iter2 = Iter2.Left; + } + else if (Iter1.Col < Iter2.Col) + { + Res.Insert(Iter2.Row, Iter2.Col, Iter2.Val); + Iter2 = Iter2.Left; + } + else //(Iter2.Col < Iter1.Col) + { + Res.Insert(Iter1.Row, Iter1.Col, Iter1.Val); + Iter1 = Iter1.Left; + } + } + } + return Res; + } + /// + /// Substacts two matrixes + /// + /// first matrix + /// second matrix + /// result of substruction of this matrixes + public static KnuthSparseMatrix operator -(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2) + { + if (mtx1.Rows.Count != mtx2.Rows.Count || mtx1.Cols.Count != mtx2.Cols.Count) + throw new Exception("Wrong size of matrix to summ"); + return mtx1 + (-mtx2); + } + + /// + /// Change signs of all values to opposite + /// + /// + /// + public static KnuthSparseMatrix operator -(KnuthSparseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + KnuthSparseMatrix res = new KnuthSparseMatrix(rightSide); + res.Negate(); + return res; + } + + /// + /// Check if two matrixes is equals + /// + /// first matrix + /// second matrix + /// true if matrixes are equal, else false + public static bool operator ==(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2) + { + if (mtx1.Rows.Count != mtx2.Rows.Count || mtx1.Cols.Count != mtx2.Cols.Count) + return false; + KnuthNode Iter1, Iter2; + //check rows + for (int i = 0; i < mtx1.Rows.Count; ++i) + { + Iter1 = mtx1.Rows[i]; + Iter2 = mtx2.Rows[i]; + //empty and not empty row + if (Iter1.Left == Iter1 && Iter2.Left != Iter2) + return false; + if (Iter2.Left == Iter2 && Iter1.Left != Iter1) + return false; + while (Iter1.Left != mtx1.Rows[i]) + { + //row of second mtx allready ends + if (Iter2.Left == mtx2.Rows[i]) + return false; + //not equal elements + if (Iter1 != Iter2) + return false; + Iter1 = Iter1.Left; + Iter2 = Iter2.Left; + } + //row of second mtx not allready ends + if (Iter2.Left != mtx2.Rows[i]) + return false; + } + //check cols + for (int i = 0; i < mtx1.Cols.Count; ++i) + { + Iter1 = mtx1.Cols[i]; + Iter2 = mtx2.Cols[i]; + //empty and not empty coll + if (Iter1.Up == Iter1 && Iter2.Up != Iter2) + return false; + if (Iter2.Up == Iter2 && Iter1.Up != Iter1) + return false; + while (Iter1.Up != mtx1.Cols[i]) + { + //coll of second mtx allready ends + if (Iter2.Up == mtx2.Cols[i]) + return false; + //not equal elements + if (Iter1 != Iter2) + return false; + Iter1 = Iter1.Up; + Iter2 = Iter2.Up; + } + //row of second mtx not allready ends + if (Iter2.Up != mtx2.Cols[i]) + return false; + } + //all elements are equals + return true; + } + /// + /// Check if two matrixes aren`t equals + /// + /// first matrix + /// second matrix + /// true if matrixes are not equals, else - false + public static bool operator !=(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2) + { + return !(mtx1 == mtx2); + } + + /// + /// Get current matrix in full standart form + /// + /// matrix in full form + public double[][] getFullMatrix() + { + double[][] res = new double[Rows.Count][]; + for (int i = 0; i < Rows.Count; ++i) + { + res[i] = new double[Cols.Count]; + } + //initialize + KnuthNode iterator; + for (int i = 0; i < Rows.Count; ++i) + { + iterator = Rows[i].Left; + while (iterator != Rows[i]) + { + res[iterator.Row][iterator.Col] = iterator.Val; + iterator = iterator.Left; + } + } + return res; + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 18d2fdbb..9fceefce 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,8 @@ + +