Spiking Neuron Network Simulator  1.0
Simulation and training of spiking neuron networks, primarily theta neurons
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
Matrix.cs
Go to the documentation of this file.
1 /*
2  Matrix class in C#
3  Written by Ivan Kuckir (ivan.kuckir@gmail.com, http://blog.ivank.net)
4  Faculty of Mathematics and Physics
5  Charles University in Prague
6  (C) 2010
7  - updated on 14.6.2012 - parsing improved. Thanks to Andy!
8  - updated on 3.10.2012 - there was a terrible bug in LU, SoLE and Inversion. Thanks to Danilo Neves Cruz for reporting that!
9 
10  Updated by Sam McKennoch Early 2014
11  - update to correct Resharper Issues
12  - updated RandomMatrix to accept double dispersion and probability parameter
13  - added GetRow
14  - added ConstantMatrix and double + Matrix
15  - added ==, !=, Equals, GetHashCode
16  - added xml comments throughout
17  - Minor refactoring
18 
19  This code is distributed under MIT licence.
20 
21 
22  Permission is hereby granted, free of charge, to any person
23  obtaining a copy of this software and associated documentation
24  files (the "Software"), to deal in the Software without
25  restriction, including without limitation the rights to use,
26  copy, modify, merge, publish, distribute, sublicense, and/or sell
27  copies of the Software, and to permit persons to whom the
28  Software is furnished to do so, subject to the following
29  conditions:
30 
31  The above copyright notice and this permission notice shall be
32  included in all copies or substantial portions of the Software.
33 
34  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
36  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
38  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
39  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
40  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41  OTHER DEALINGS IN THE SOFTWARE.
42 */
43 
44 namespace SpikingNeuronNetwork.Lib
45 {
46  using System;
47  using System.Collections.Generic;
48  using System.Text.RegularExpressions;
49 
53  public class Matrix
54  {
55  private const double Epsilon = 1e-5;
56  private Matrix L;
57  private Matrix U;
58  private double _detOfP = 1;
59  private int[] _pi;
60  private double[,] Mat { get; set; }
61 
67  public Matrix(int iRows, int iCols)
68  {
69  Mat = new double[iRows, iCols];
70  }
71 
75  public int Rows
76  {
77  get { return Mat.GetLength(0); }
78  }
79 
83  public int Cols
84  {
85  get { return Mat.GetLength(1); }
86  }
87 
91  public bool IsSquare
92  {
93  get { return (Rows == Cols); }
94  }
95 
102  public double this[int iRow, int iCol] // Access this matrix as a 2D array
103  {
104  get { return Mat[iRow, iCol]; }
105  set { Mat[iRow, iCol] = value; }
106  }
107 
113  public override bool Equals(object obj)
114  {
115  if (ReferenceEquals(null, obj)) return false;
116  if (ReferenceEquals(this, obj)) return true;
117  return obj.GetType() == GetType() && Equals((Matrix)obj);
118  }
119 
120  protected bool Equals(Matrix m1)
121  {
122  return this == m1;
123  }
124 
129  public override int GetHashCode()
130  {
131  unchecked
132  {
133  var hashCode = (Mat != null ? Mat.GetHashCode() : 0);
134  hashCode = (hashCode * 397) ^ Rows;
135  hashCode = (hashCode * 397) ^ Cols;
136  return hashCode;
137  }
138  }
139 
145  public Matrix GetRow(int k)
146  {
147  var m = new Matrix(1, Cols);
148  for (var i = 0; i < Cols; i++) m[0, i] = Mat[k, i];
149  return m;
150  }
151 
157  public Matrix GetCol(int k)
158  {
159  var m = new Matrix(Rows, 1);
160  for (var i = 0; i < Rows; i++) m[i, 0] = Mat[i, k];
161  return m;
162  }
163 
169  public List<int> FindAllIndexOf(double val)
170  {
171  var indices = new List<int>();
172  for (var row = 0; row < Rows; row ++)
173  {
174  for (var col = 0; col < Cols; col++)
175  {
176  if (Math.Abs(Mat[row, col] - val) < Epsilon)
177  {
178  indices.Add(col + row*Cols);
179  }
180  }
181  }
182  return indices;
183  }
184 
190  public List<int> FindAllIndexOfNot(double val)
191  {
192  var indices = new List<int>();
193  for (var row = 0; row < Rows; row++)
194  {
195  for (var col = 0; col < Cols; col++)
196  {
197  if (Math.Abs(Mat[row, col] - val) >= Epsilon)
198  {
199  indices.Add(col + row * Cols);
200  }
201  }
202  }
203  return indices;
204  }
205 
211  public void SetCol(Matrix v, int k)
212  {
213  for (var i = 0; i < Rows; i++) Mat[i, k] = v[i, 0];
214  }
215 
219  public void MakeLU()
220  {
221  if (!IsSquare) throw new MatrixException("The matrix is not square!");
222  L = IdentityMatrix(Rows, Cols);
223  U = Clone();
224 
225  _pi = new int[Rows];
226  for (var i = 0; i < Rows; i++) _pi[i] = i;
227 
228  var k0 = 0;
229 
230  for (var k = 0; k < Cols - 1; k++)
231  {
232  double p = 0;
233  for (var i = k; i < Rows; i++) // find the row with the biggest pivot
234  {
235  if (Math.Abs(U[i, k]) > p)
236  {
237  p = Math.Abs(U[i, k]);
238  k0 = i;
239  }
240  }
241  if (Math.Abs(p - 0) < Epsilon) // samé nuly ve sloupci
242  throw new MatrixException("The matrix is singular!");
243 
244  var pom1 = _pi[k];
245  _pi[k] = _pi[k0];
246  _pi[k0] = pom1; // switch two rows in permutation matrix
247 
248  double pom2;
249  for (var i = 0; i < k; i++)
250  {
251  pom2 = L[k, i];
252  L[k, i] = L[k0, i];
253  L[k0, i] = pom2;
254  }
255 
256  if (k != k0) _detOfP *= -1;
257 
258  for (var i = 0; i < Cols; i++) // Switch rows in U
259  {
260  pom2 = U[k, i];
261  U[k, i] = U[k0, i];
262  U[k0, i] = pom2;
263  }
264 
265  for (var i = k + 1; i < Rows; i++)
266  {
267  L[i, k] = U[i, k]/U[k, k];
268  for (var j = k; j < Cols; j++)
269  U[i, j] = U[i, j] - L[i, k]*U[k, j];
270  }
271  }
272  }
273 
280  {
281  if (Rows != Cols) throw new MatrixException("The matrix is not square!");
282  if (Rows != v.Rows) throw new MatrixException("Wrong number of results in solution vector!");
283  if (L == null) MakeLU();
284 
285  var b = new Matrix(Rows, 1);
286  for (var i = 0; i < Rows; i++) b[i, 0] = v[_pi[i], 0]; // switch two items in "v" due to permutation matrix
287 
288  var z = SubsForth(L, b);
289  var x = SubsBack(U, z);
290 
291  return x;
292  }
293 
298  public Matrix Invert()
299  {
300  if (L == null) MakeLU();
301 
302  var inv = new Matrix(Rows, Cols);
303 
304  for (var i = 0; i < Rows; i++)
305  {
306  var ei = ZeroMatrix(Rows, 1);
307  ei[i, 0] = 1;
308  var col = SolveWith(ei);
309  inv.SetCol(col, i);
310  }
311  return inv;
312  }
313 
318  public double Det()
319  {
320  if (L == null) MakeLU();
321  var det = _detOfP;
322  for (var i = 0; i < Rows; i++) det *= U[i, i];
323  return det;
324  }
325 
331  {
332  if (L == null) MakeLU();
333 
334  var matrix = ZeroMatrix(Rows, Cols);
335  for (var i = 0; i < Rows; i++) matrix[_pi[i], i] = 1;
336  return matrix;
337  }
338 
343  public Matrix Clone()
344  {
345  var matrix = new Matrix(Rows, Cols);
346  for (var i = 0; i < Rows; i++)
347  for (var j = 0; j < Cols; j++)
348  matrix[i, j] = Mat[i, j];
349  return matrix;
350  }
351 
358  public static Matrix SubsForth(Matrix mA, Matrix b)
359  {
360  if (mA.L == null) mA.MakeLU();
361  var n = mA.Rows;
362  var x = new Matrix(n, 1);
363 
364  for (var i = 0; i < n; i++)
365  {
366  x[i, 0] = b[i, 0];
367  for (var j = 0; j < i; j++) x[i, 0] -= mA[i, j]*x[j, 0];
368  x[i, 0] = x[i, 0]/mA[i, i];
369  }
370  return x;
371  }
372 
379  public static Matrix SubsBack(Matrix mA, Matrix b)
380  {
381  if (mA.L == null) mA.MakeLU();
382  var n = mA.Rows;
383  var x = new Matrix(n, 1);
384 
385  for (var i = n - 1; i > -1; i--)
386  {
387  x[i, 0] = b[i, 0];
388  for (var j = n - 1; j > i; j--) x[i, 0] -= mA[i, j]*x[j, 0];
389  x[i, 0] = x[i, 0]/mA[i, i];
390  }
391  return x;
392  }
393 
400  public static Matrix ZeroMatrix(int iRows, int iCols)
401  {
402  var matrix = new Matrix(iRows, iCols);
403  for (var i = 0; i < iRows; i++)
404  for (var j = 0; j < iCols; j++)
405  matrix[i, j] = 0;
406  return matrix;
407  }
408 
416  public static Matrix ConstantMatrix(int iRows, int iCols, double val)
417  {
418  var matrix = new Matrix(iRows, iCols);
419  for (var i = 0; i < iRows; i++)
420  for (var j = 0; j < iCols; j++)
421  matrix[i, j] = val;
422  return matrix;
423  }
424 
431  public static Matrix IdentityMatrix(int iRows, int iCols)
432  {
433  var matrix = ZeroMatrix(iRows, iCols);
434  for (var i = 0; i < Math.Min(iRows, iCols); i++)
435  matrix[i, i] = 1;
436  return matrix;
437  }
438 
447  public static Matrix RandomMatrix(int iRows, int iCols, double dispersion, double probability = 1.0)
448  {
449  var random = new Random();
450  var matrix = new Matrix(iRows, iCols);
451  for (var i = 0; i < iRows; i++)
452  for (var j = 0; j < iCols; j++)
453  matrix[i, j] = (random.NextDouble() <= probability) ? dispersion*2*(random.NextDouble() - 0.5) : 0;
454  return matrix;
455  }
456 
462  public static Matrix Parse(string ps)
463  {
464  var s = NormalizeMatrixString(ps);
465  var rows = Regex.Split(s, "\r\n");
466  var nums = rows[0].Split(' ');
467  var matrix = new Matrix(rows.Length, nums.Length);
468  try
469  {
470  for (var i = 0; i < rows.Length; i++)
471  {
472  nums = rows[i].Split(' ');
473  for (var j = 0; j < nums.Length; j++) matrix[i, j] = double.Parse(nums[j]);
474  }
475  }
476  catch (FormatException)
477  {
478  throw new MatrixException("Wrong input format!");
479  }
480  return matrix;
481  }
482 
487  public override string ToString()
488  {
489  string s = "";
490  for (int i = 0; i < Rows; i++)
491  {
492  for (int j = 0; j < Cols; j++) s += String.Format("{0,5:0.00}", Mat[i, j]) + " ";
493  s += "\r\n";
494  }
495  return s;
496  }
497 
503  public static Matrix Transpose(Matrix m)
504  {
505  var t = new Matrix(m.Cols, m.Rows);
506  for (int i = 0; i < m.Rows; i++)
507  for (int j = 0; j < m.Cols; j++)
508  t[j, i] = m[i, j];
509  return t;
510  }
511 
518  public static Matrix Power(Matrix m, int pow)
519  {
520  if (pow == 0) return IdentityMatrix(m.Rows, m.Cols);
521  if (pow == 1) return m.Clone();
522  if (pow == -1) return m.Invert();
523 
524  Matrix x;
525  if (pow < 0)
526  {
527  x = m.Invert();
528  pow *= -1;
529  }
530  else x = m.Clone();
531 
532  // ToDo: This would be much faster with a decomposition
533  Matrix ret = IdentityMatrix(m.Rows, m.Cols);
534  while (pow != 0)
535  {
536  if ((pow & 1) == 1) ret *= x;
537  x *= x;
538  pow >>= 1;
539  }
540  return ret;
541  }
542 
543  private static void SafeAplusBintoC(Matrix mA, int xa, int ya, Matrix mB, int xb, int yb, Matrix mC, int size)
544  {
545  for (int i = 0; i < size; i++) // rows
546  for (int j = 0; j < size; j++) // cols
547  {
548  mC[i, j] = 0;
549  if (xa + j < mA.Cols && ya + i < mA.Rows) mC[i, j] += mA[ya + i, xa + j];
550  if (xb + j < mB.Cols && yb + i < mB.Rows) mC[i, j] += mB[yb + i, xb + j];
551  }
552  }
553 
554  private static void SafeAminusBintoC(Matrix mA, int xa, int ya, Matrix mB, int xb, int yb, Matrix mC, int size)
555  {
556  for (int i = 0; i < size; i++) // rows
557  for (int j = 0; j < size; j++) // cols
558  {
559  mC[i, j] = 0;
560  if (xa + j < mA.Cols && ya + i < mA.Rows) mC[i, j] += mA[ya + i, xa + j];
561  if (xb + j < mB.Cols && yb + i < mB.Rows) mC[i, j] -= mB[yb + i, xb + j];
562  }
563  }
564 
565  private static void SafeACopytoC(Matrix mA, int xa, int ya, Matrix mC, int size)
566  {
567  for (int i = 0; i < size; i++) // rows
568  for (int j = 0; j < size; j++) // cols
569  {
570  mC[i, j] = 0;
571  if (xa + j < mA.Cols && ya + i < mA.Rows) mC[i, j] += mA[ya + i, xa + j];
572  }
573  }
574 
575  private static void AplusBintoC(Matrix mA, int xa, int ya, Matrix mB, int xb, int yb, Matrix mC, int size)
576  {
577  for (int i = 0; i < size; i++) // rows
578  for (int j = 0; j < size; j++) mC[i, j] = mA[ya + i, xa + j] + mB[yb + i, xb + j];
579  }
580 
581  private static void AminusBintoC(Matrix mA, int xa, int ya, Matrix mB, int xb, int yb, Matrix mC, int size)
582  {
583  for (int i = 0; i < size; i++) // rows
584  for (int j = 0; j < size; j++) mC[i, j] = mA[ya + i, xa + j] - mB[yb + i, xb + j];
585  }
586 
587  private static void ACopytoC(Matrix mA, int xa, int ya, Matrix mC, int size)
588  {
589  for (int i = 0; i < size; i++) // rows
590  for (int j = 0; j < size; j++) mC[i, j] = mA[ya + i, xa + j];
591  }
592 
593  private static Matrix StrassenMultiply(Matrix mA, Matrix mB) // Smart matrix multiplication
594  {
595  if (mA.Cols != mB.Rows) throw new MatrixException("Wrong dimension of matrix!");
596 
597  Matrix mR;
598 
599  int msize = Math.Max(Math.Max(mA.Rows, mA.Cols), Math.Max(mB.Rows, mB.Cols));
600 
601  if (msize < 32)
602  {
603  mR = ZeroMatrix(mA.Rows, mB.Cols);
604  for (int i = 0; i < mR.Rows; i++)
605  for (int j = 0; j < mR.Cols; j++)
606  for (int k = 0; k < mA.Cols; k++)
607  mR[i, j] += mA[i, k]*mB[k, j];
608  return mR;
609  }
610 
611  int size = 1;
612  int n = 0;
613  while (msize > size)
614  {
615  size *= 2;
616  n++;
617  }
618 
619  var h = size/2;
620 
621 
622  var mField = new Matrix[n,9];
623 
624  /*
625  * 8x8, 8x8, 8x8, ...
626  * 4x4, 4x4, 4x4, ...
627  * 2x2, 2x2, 2x2, ...
628  * . . .
629  */
630 
631  for (var i = 0; i < n - 4; i++) // rows
632  {
633  var z = (int) Math.Pow(2, n - i - 1);
634  for (int j = 0; j < 9; j++) mField[i, j] = new Matrix(z, z);
635  }
636 
637  SafeAplusBintoC(mA, 0, 0, mA, h, h, mField[0, 0], h);
638  SafeAplusBintoC(mB, 0, 0, mB, h, h, mField[0, 1], h);
639  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 1], 1, mField); // (A11 + A22) * (B11 + B22);
640 
641  SafeAplusBintoC(mA, 0, h, mA, h, h, mField[0, 0], h);
642  SafeACopytoC(mB, 0, 0, mField[0, 1], h);
643  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 2], 1, mField); // (A21 + A22) * B11;
644 
645  SafeACopytoC(mA, 0, 0, mField[0, 0], h);
646  SafeAminusBintoC(mB, h, 0, mB, h, h, mField[0, 1], h);
647  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 3], 1, mField); //A11 * (B12 - B22);
648 
649  SafeACopytoC(mA, h, h, mField[0, 0], h);
650  SafeAminusBintoC(mB, 0, h, mB, 0, 0, mField[0, 1], h);
651  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 4], 1, mField); //A22 * (B21 - B11);
652 
653  SafeAplusBintoC(mA, 0, 0, mA, h, 0, mField[0, 0], h);
654  SafeACopytoC(mB, h, h, mField[0, 1], h);
655  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 5], 1, mField); //(A11 + A12) * B22;
656 
657  SafeAminusBintoC(mA, 0, h, mA, 0, 0, mField[0, 0], h);
658  SafeAplusBintoC(mB, 0, 0, mB, h, 0, mField[0, 1], h);
659  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 6], 1, mField); //(A21 - A11) * (B11 + B12);
660 
661  SafeAminusBintoC(mA, h, 0, mA, h, h, mField[0, 0], h);
662  SafeAplusBintoC(mB, 0, h, mB, h, h, mField[0, 1], h);
663  StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 7], 1, mField); // (A12 - A22) * (B21 + B22);
664 
665  mR = new Matrix(mA.Rows, mB.Cols); // result
666 
667  // C11
668  for (int i = 0; i < Math.Min(h, mR.Rows); i++) // rows
669  for (int j = 0; j < Math.Min(h, mR.Cols); j++) // cols
670  mR[i, j] = mField[0, 1 + 1][i, j] + mField[0, 1 + 4][i, j] - mField[0, 1 + 5][i, j] +
671  mField[0, 1 + 7][i, j];
672 
673  // C12
674  for (int i = 0; i < Math.Min(h, mR.Rows); i++) // rows
675  for (int j = h; j < Math.Min(2*h, mR.Cols); j++) // cols
676  mR[i, j] = mField[0, 1 + 3][i, j - h] + mField[0, 1 + 5][i, j - h];
677 
678  // C21
679  for (int i = h; i < Math.Min(2*h, mR.Rows); i++) // rows
680  for (int j = 0; j < Math.Min(h, mR.Cols); j++) // cols
681  mR[i, j] = mField[0, 1 + 2][i - h, j] + mField[0, 1 + 4][i - h, j];
682 
683  // C22
684  for (int i = h; i < Math.Min(2*h, mR.Rows); i++) // rows
685  for (int j = h; j < Math.Min(2*h, mR.Cols); j++) // cols
686  mR[i, j] = mField[0, 1 + 1][i - h, j - h] - mField[0, 1 + 2][i - h, j - h] +
687  mField[0, 1 + 3][i - h, j - h] + mField[0, 1 + 6][i - h, j - h];
688 
689  return mR;
690  }
691 
692  // function for square matrix 2^N x 2^N
693 
694  private static void StrassenMultiplyRun(Matrix mA, Matrix mB, Matrix mC, int l, Matrix[,] f)
695  // A * B into C, level of recursion, matrix field
696  {
697  int size = mA.Rows;
698  int h = size/2;
699 
700  if (size < 32)
701  {
702  for (int i = 0; i < mC.Rows; i++)
703  for (int j = 0; j < mC.Cols; j++)
704  {
705  mC[i, j] = 0;
706  for (int k = 0; k < mA.Cols; k++) mC[i, j] += mA[i, k]*mB[k, j];
707  }
708  return;
709  }
710 
711  AplusBintoC(mA, 0, 0, mA, h, h, f[l, 0], h);
712  AplusBintoC(mB, 0, 0, mB, h, h, f[l, 1], h);
713  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 1], l + 1, f); // (A11 + A22) * (B11 + B22);
714 
715  AplusBintoC(mA, 0, h, mA, h, h, f[l, 0], h);
716  ACopytoC(mB, 0, 0, f[l, 1], h);
717  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 2], l + 1, f); // (A21 + A22) * B11;
718 
719  ACopytoC(mA, 0, 0, f[l, 0], h);
720  AminusBintoC(mB, h, 0, mB, h, h, f[l, 1], h);
721  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 3], l + 1, f); //A11 * (B12 - B22);
722 
723  ACopytoC(mA, h, h, f[l, 0], h);
724  AminusBintoC(mB, 0, h, mB, 0, 0, f[l, 1], h);
725  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 4], l + 1, f); //A22 * (B21 - B11);
726 
727  AplusBintoC(mA, 0, 0, mA, h, 0, f[l, 0], h);
728  ACopytoC(mB, h, h, f[l, 1], h);
729  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 5], l + 1, f); //(A11 + A12) * B22;
730 
731  AminusBintoC(mA, 0, h, mA, 0, 0, f[l, 0], h);
732  AplusBintoC(mB, 0, 0, mB, h, 0, f[l, 1], h);
733  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 6], l + 1, f); //(A21 - A11) * (B11 + B12);
734 
735  AminusBintoC(mA, h, 0, mA, h, h, f[l, 0], h);
736  AplusBintoC(mB, 0, h, mB, h, h, f[l, 1], h);
737  StrassenMultiplyRun(f[l, 0], f[l, 1], f[l, 1 + 7], l + 1, f); // (A12 - A22) * (B21 + B22);
738 
739  // C11
740  for (int i = 0; i < h; i++) // rows
741  for (int j = 0; j < h; j++) // cols
742  mC[i, j] = f[l, 1 + 1][i, j] + f[l, 1 + 4][i, j] - f[l, 1 + 5][i, j] + f[l, 1 + 7][i, j];
743 
744  // C12
745  for (int i = 0; i < h; i++) // rows
746  for (int j = h; j < size; j++) // cols
747  mC[i, j] = f[l, 1 + 3][i, j - h] + f[l, 1 + 5][i, j - h];
748 
749  // C21
750  for (int i = h; i < size; i++) // rows
751  for (int j = 0; j < h; j++) // cols
752  mC[i, j] = f[l, 1 + 2][i - h, j] + f[l, 1 + 4][i - h, j];
753 
754  // C22
755  for (int i = h; i < size; i++) // rows
756  for (int j = h; j < size; j++) // cols
757  mC[i, j] = f[l, 1 + 1][i - h, j - h] - f[l, 1 + 2][i - h, j - h] + f[l, 1 + 3][i - h, j - h] +
758  f[l, 1 + 6][i - h, j - h];
759  }
760 
761  private static Matrix Multiply(double n, Matrix m) // Multiplication by constant n
762  {
763  var r = new Matrix(m.Rows, m.Cols);
764  for (int i = 0; i < m.Rows; i++)
765  for (int j = 0; j < m.Cols; j++)
766  r[i, j] = m[i, j]*n;
767  return r;
768  }
769 
770  private static Matrix Add(Matrix m1, Matrix m2) // Sčítání matic
771  {
772  if (m1.Rows != m2.Rows || m1.Cols != m2.Cols)
773  throw new MatrixException("Matrices must have the same dimensions!");
774  var r = new Matrix(m1.Rows, m1.Cols);
775  for (int i = 0; i < r.Rows; i++)
776  for (int j = 0; j < r.Cols; j++)
777  r[i, j] = m1[i, j] + m2[i, j];
778  return r;
779  }
780 
781  private static string NormalizeMatrixString(string matStr) // From Andy - thank you! :)
782  {
783  // Remove any multiple spaces
784  while (matStr.IndexOf(" ", StringComparison.Ordinal) != -1)
785  matStr = matStr.Replace(" ", " ");
786 
787  // Remove any spaces before or after newlines
788  matStr = matStr.Replace(" \r\n", "\r\n");
789  matStr = matStr.Replace("\r\n ", "\r\n");
790 
791  // If the data ends in a newline, remove the trailing newline.
792  // Make it easier by first replacing \r\n’s with |’s then
793  // restore the |’s with \r\n’s
794  matStr = matStr.Replace("\r\n", "|");
795  while (matStr.LastIndexOf("|", StringComparison.Ordinal) == (matStr.Length - 1))
796  matStr = matStr.Substring(0, matStr.Length - 1);
797 
798  matStr = matStr.Replace("|", "\r\n");
799  return matStr;
800  }
801 
802  #region operators
803 
809  public static Matrix operator -(Matrix m)
810  {
811  return Multiply(-1, m);
812  }
813 
820  public static Matrix operator +(double m1, Matrix m2)
821  {
822  var m3 = new Matrix(m2.Rows, m2.Cols);
823  for (var i = 0; i < m2.Rows; i++)
824  for (var j = 0; j < m2.Cols; j++)
825  m3[i, j] = m2[i,j] + m1;
826  return m2;
827  }
828 
835  public static Matrix operator +(Matrix m1, double m2)
836  {
837  return m2 + m1;
838  }
839 
846  public static Matrix operator +(Matrix m1, Matrix m2)
847  {
848  return Add(m1, m2);
849  }
850 
857  public static Matrix operator -(Matrix m1, Matrix m2)
858  {
859  return Add(m1, -m2);
860  }
861 
868  public static Matrix operator *(Matrix m1, Matrix m2)
869  {
870  return StrassenMultiply(m1, m2);
871  }
872 
879  public static Matrix operator *(double n, Matrix m)
880  {
881  return Multiply(n, m);
882  }
883 
890  public static bool operator ==(Matrix m1, Matrix m2)
891  {
892  if (m1 == null || m2 == null || m1.Rows != m2.Rows || m1.Cols != m2.Cols)
893  throw new MatrixException("Matrices must have the same dimensions!");
894  for (var i = 0; i < m1.Rows; i++)
895  for (var j = 0; j < m1.Cols; j++)
896  if (Math.Abs(m1[i, j] - m2[i, j]) > Epsilon) return false;
897  return true;
898  }
899 
906  public static bool operator !=(Matrix m1, Matrix m2)
907  {
908  return !(m1 == m2);
909  }
910 
911  #endregion
912  }
913 }
static Matrix IdentityMatrix(int iRows, int iCols)
Gets an indentity matrix of size iRows by iCols
Definition: Matrix.cs:431
Matrix SolveWith(Matrix v)
Solve Ax = v for x, where A is the current matrix
Definition: Matrix.cs:279
double Det()
Calculates the matrix determinant
Definition: Matrix.cs:318
Matrix Clone()
Gets a deep copy of the matrix
Definition: Matrix.cs:343
Matrix GetCol(int k)
Gets a column matrix
Definition: Matrix.cs:157
static Matrix Transpose(Matrix m)
Gets a transposed matrix
Definition: Matrix.cs:503
override string ToString()
Returns a string representation of the matrix
Definition: Matrix.cs:487
Matrix Invert()
Inverts the current matrix
Definition: Matrix.cs:298
override bool Equals(object obj)
Indicates if a matrix is equal to an object
Definition: Matrix.cs:113
bool Equals(Matrix m1)
Definition: Matrix.cs:120
int Cols
Gets the number of columns in the matrix
Definition: Matrix.cs:84
override int GetHashCode()
Gets a hash code representation of the matrix
Definition: Matrix.cs:129
static Matrix SubsBack(Matrix mA, Matrix b)
Solves Ax = b for A as an upper triangular matrix
Definition: Matrix.cs:379
static Matrix ZeroMatrix(int iRows, int iCols)
Gets a matrix of zeros of size iRows by iCols
Definition: Matrix.cs:400
Matrix(int iRows, int iCols)
Creates a new instance of Matrix of size iRows and iCols
Definition: Matrix.cs:67
static Matrix Power(Matrix m, int pow)
Gets a matrix raised to an integer power
Definition: Matrix.cs:518
Matrix GetRow(int k)
Gets a row matrix
Definition: Matrix.cs:145
static Matrix ConstantMatrix(int iRows, int iCols, double val)
Gets a matrix of constant values equal to val of size iRows by iCols
Definition: Matrix.cs:416
void MakeLU()
Perform LU Decomposition
Definition: Matrix.cs:219
Matrix GetPermutationMatrix()
Gets a permutation matrix "P" due to permutation vector "pi"
Definition: Matrix.cs:330
void SetCol(Matrix v, int k)
Sets a column of the matrix to a given column matrix
Definition: Matrix.cs:211
static Matrix RandomMatrix(int iRows, int iCols, double dispersion, double probability=1.0)
Gets a matrix of random numbers of size iRows by iCols
Definition: Matrix.cs:447
List< int > FindAllIndexOfNot(double val)
Gets a list of a indices where the value is not equal to val within epsilon
Definition: Matrix.cs:190
int Rows
Gets the number of rows in the matrix
Definition: Matrix.cs:76
static Matrix SubsForth(Matrix mA, Matrix b)
Solves Ax = b for A as a lower triangular matrix
Definition: Matrix.cs:358
static Matrix Parse(string ps)
Gets a matrix as parsed from a string delimited by spaces and newlines
Definition: Matrix.cs:462
List< int > FindAllIndexOf(double val)
Gets a list of a indices where the value is equal to val within epsilon
Definition: Matrix.cs:169