diff --git a/Exceptions/ColumnZeroSizeException.cs b/Exceptions/ColumnZeroSizeException.cs
new file mode 100644
index 0000000..e74b607
--- /dev/null
+++ b/Exceptions/ColumnZeroSizeException.cs
@@ -0,0 +1,20 @@
+using System;
+
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Появляется при попытке создать
+ /// столбец с нулевыми размерами
+ ///
+ public class ColumnZeroSizeException : Exception
+ {
+ private string _message = "Columns can not be zero size";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message => _message;
+
+ }
+}
diff --git a/Exceptions/ColumnsOfDifferentSizesException.cs b/Exceptions/ColumnsOfDifferentSizesException.cs
new file mode 100644
index 0000000..e47e737
--- /dev/null
+++ b/Exceptions/ColumnsOfDifferentSizesException.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Появляется при попытке сложить/вычесть строки разных размеров
+ ///
+ public class ColumnsOfDifferentSizesException : Exception
+ {
+ private string _message = "Columns must be the same sizes.";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message
+ {
+ get => _message;
+ }
+ }
+}
diff --git a/Exceptions/MatrixDifferentSizeException.cs b/Exceptions/MatrixDifferentSizeException.cs
index 9605002..3020302 100644
--- a/Exceptions/MatrixDifferentSizeException.cs
+++ b/Exceptions/MatrixDifferentSizeException.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace MathExtended.Exceptions
{
@@ -12,12 +8,11 @@ namespace MathExtended.Exceptions
public class MatrixDifferentSizeException : Exception
{
private string message = "Matrices must be the same size";
+
///
/// Сообщение исключения
///
- public override string Message
- {
- get => message;
- }
+ public override string Message => message;
+
}
}
diff --git a/Exceptions/MatrixInvalidSizesException.cs b/Exceptions/MatrixInvalidSizesException.cs
new file mode 100644
index 0000000..c3c8d0f
--- /dev/null
+++ b/Exceptions/MatrixInvalidSizesException.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Возникает при попытке создать матрицу
+ /// с нулевыми размерами
+ ///
+ public class MatrixInvalidSizesException : Exception
+ {
+ private string _message = "Matrices can not be zero or less zero size.";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message => _message;
+
+ }
+}
diff --git a/Exceptions/RowZeroSizeException.cs b/Exceptions/RowZeroSizeException.cs
new file mode 100644
index 0000000..40be7e3
--- /dev/null
+++ b/Exceptions/RowZeroSizeException.cs
@@ -0,0 +1,19 @@
+using System;
+
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Появляется при попытке создать строку с нулевой длиной
+ ///
+ public class RowZeroSizeException : Exception
+ {
+ private string _message = "Rows can not be zero size.";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message => _message;
+
+ }
+}
diff --git a/Exceptions/RowsOfDifferentSizesException.cs b/Exceptions/RowsOfDifferentSizesException.cs
new file mode 100644
index 0000000..2e7f0b4
--- /dev/null
+++ b/Exceptions/RowsOfDifferentSizesException.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Появляется при попытке сложить/вычесть строки разных размеров
+ ///
+ public class RowsOfDifferentSizesException : Exception
+ {
+ private string _message = "Rows must be the same sizes.";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message
+ {
+ get => _message;
+ }
+ }
+}
diff --git a/Exceptions/TheNumberOfRowsAndColumnsIsDifferentException.cs b/Exceptions/TheNumberOfRowsAndColumnsIsDifferentException.cs
index acb7cf5..82e63a6 100644
--- a/Exceptions/TheNumberOfRowsAndColumnsIsDifferentException.cs
+++ b/Exceptions/TheNumberOfRowsAndColumnsIsDifferentException.cs
@@ -1,8 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+
namespace MathExtended.Exceptions
{
diff --git a/Exceptions/VectorsDifferentSizeException.cs b/Exceptions/VectorsDifferentSizeException.cs
new file mode 100644
index 0000000..d9fb266
--- /dev/null
+++ b/Exceptions/VectorsDifferentSizeException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace MathExtended.Exceptions
+{
+ ///
+ /// Возникает при попытке операции
+ /// над вектор строками/столбцами разных размеров
+ ///
+ public class VectorsDifferentSizeException : Exception
+ {
+ private string _message = "Vector row/column of different sizes";
+
+ ///
+ /// Сообщение исключения
+ ///
+ public override string Message => _message;
+ }
+}
diff --git a/ExtendentRandom.cs b/ExtendentRandom.cs
new file mode 100644
index 0000000..9935290
--- /dev/null
+++ b/ExtendentRandom.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace MathExtended
+{
+ ///
+ /// Улучшенная версия Random
+ ///
+ public class ExtendentRandom : Random
+ {
+ ///
+ /// Генерирует случайное число типа
+ /// в заданных границах
+ ///
+ /// Числовой тип
+ /// Нижняя граница
+ /// Верхняя граница
+ /// Число
+ public T Next(in T minValue, in T maxValue) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ if ((dynamic)minValue < maxValue)
+ {
+ var minValueCasted = (double)(dynamic)minValue;
+ var maxValueCasted = (double)(dynamic)maxValue;
+ var random = base.NextDouble();
+ return (T)(dynamic)((random * minValueCasted) + (1 - random) * maxValueCasted);//System.EngineError (Ненормальное потребление памяти)
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ ///
+ /// Генерирует случайное число типа
+ ///
+ /// Числовой тип
+ /// Число
+ public T Next() where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ return (T)(dynamic)(base.Next() + base.NextDouble());
+ }
+ }
+}
diff --git a/Interfaces/IMatrix.cs b/Interfaces/IMatrix.cs
new file mode 100644
index 0000000..39f71be
--- /dev/null
+++ b/Interfaces/IMatrix.cs
@@ -0,0 +1,42 @@
+using MathExtended.Matrices.Structures.CellsCollections;
+using System;
+using System.Collections.Generic;
+
+namespace MathExtended.Interfaces
+{
+ ///
+ /// Определяет основную структуру матрицы
+ ///
+ /// Числовой тип
+ public interface IMatrix : IEnumerable, IEnumerator where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ ///
+ /// Главная диагональ
+ ///
+ MainDiagonal MainDiagonal { get; }
+
+ ///
+ /// Количество строк
+ ///
+ int RowsCount { get; }
+
+ ///
+ /// Количество столбцов
+ ///
+ int ColumnsCount { get; }
+
+ ///
+ /// Индесатор матрицы, получает ячейку в соответсвии с ее адресом в матрице
+ ///
+ /// Индекс строки
+ /// Индекс столбца
+ /// число по индексу
+ T this[int row, int column]
+ {
+ get;
+ set;
+ }
+
+
+ }
+}
diff --git a/MathExtended.1.0.1.1.nupkg b/MathExtended.1.0.1.1.nupkg
new file mode 100644
index 0000000..e41f4e3
Binary files /dev/null and b/MathExtended.1.0.1.1.nupkg differ
diff --git a/MathExtended.csproj b/MathExtended.csproj
index 9be168b..04f6769 100644
--- a/MathExtended.csproj
+++ b/MathExtended.csproj
@@ -9,9 +9,10 @@
Properties
MathExtended
MathExtended
- v4.7.2
+ v4.8
512
true
+
true
@@ -31,6 +32,9 @@
prompt
4
+
+ false
+
packages\JTForks.MiscUtil.1.285.0\lib\netstandard1.0\JTForks.MiscUtil.dll
@@ -46,6 +50,9 @@
True
True
+
+ packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
packages\System.Console.4.0.0\lib\net46\System.Console.dll
@@ -102,6 +109,9 @@
True
True
+
+ packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
+
packages\System.Net.Http.4.1.0\lib\net46\System.Net.Http.dll
True
@@ -113,6 +123,9 @@
True
+
+ packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
packages\System.Reflection.4.1.0\lib\net462\System.Reflection.dll
True
@@ -126,6 +139,9 @@
True
True
+
+ packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
packages\System.Runtime.Extensions.4.1.0\lib\net462\System.Runtime.Extensions.dll
True
@@ -178,14 +194,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MathExtended.nuspec b/MathExtended.nuspec
new file mode 100644
index 0000000..028e55e
--- /dev/null
+++ b/MathExtended.nuspec
@@ -0,0 +1,18 @@
+
+
+
+ $id$
+ 1.0.1.1
+ MathExtendent
+ Lamer0
+ C#
+ false
+ MIT
+ https://github.com/Lamer0/ExtendentMath
+ MathExtended
+ A math library that will include work with matrices, some trigonometric functions of which are not in Math
+
+ https://github.com/Lamer0/ExtendentMath
+ Release
+
+
\ No newline at end of file
diff --git a/MathExtended.sln b/MathExtended.sln
index 256ae81..b7d6f4b 100644
--- a/MathExtended.sln
+++ b/MathExtended.sln
@@ -1,10 +1,12 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30907.101
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32210.238
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathExtended", "MathExtended.csproj", "{CCDF7FC9-1928-43E4-9DF2-874E5A2538E3}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MathExtendentTests", "MathExtendentTests\MathExtendentTests.csproj", "{3F8BB5A8-CCE7-413B-A94B-EA13CF2BF305}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{CCDF7FC9-1928-43E4-9DF2-874E5A2538E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCDF7FC9-1928-43E4-9DF2-874E5A2538E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCDF7FC9-1928-43E4-9DF2-874E5A2538E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3F8BB5A8-CCE7-413B-A94B-EA13CF2BF305}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F8BB5A8-CCE7-413B-A94B-EA13CF2BF305}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3F8BB5A8-CCE7-413B-A94B-EA13CF2BF305}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3F8BB5A8-CCE7-413B-A94B-EA13CF2BF305}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/MathExtendent.cs b/MathExtendent.cs
index 333afde..894abba 100644
--- a/MathExtendent.cs
+++ b/MathExtendent.cs
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MathExtended.Exceptions;
namespace MathExtended
{
@@ -63,14 +59,96 @@ public static double Csch(double x)
return 1 / Sch(x);
}
+ ///
+ /// Вычисляет алгебраическую сумму функции
+ ///
+ /// Индекс суммирования
+ /// Верхняя граница
+ /// Функция
+ /// Алгебраическая сумма
+ public static double AlgebraicSum(double i, double n, Func func)
+ {
+ double sum = 0;
+
+ for (; i <= n; i++)
+ {
+ sum += func(i);
+ }
+ return sum;
+ }
+
+ ///
+ /// Вычисляет алгебраическую сумму функции
+ ///
+ /// Индекс суммирования
+ /// Нижняя граница
+ /// Верхняя граница
+ /// Функция
+ /// Алгебраическая сумма
+ public static double AlgebraicSum(double i, double min, double max, Func func)
+ {
+ double sum = 0;
+ for (; i <= max && i >= max; i++)
+ {
+ sum += func.Invoke(i);
+ }
+ return sum;
+ }
+ ///
+ /// Проводит табулирование функции
+ ///
+ /// Начальное значение
+ /// Максимальное значение
+ /// Шаг
+ /// Табулируемая функции
+ /// структура со значениями аргумента и функции
+ public static TabulateResult TabulateFunction(double x0, double xk, double dx, Func func)
+ {
+ List xValues = new List();
- }
+ List yValues = new List();
-
+ for (; x0 <= xk; x0 += dx)
+ {
+ xValues.Add(x0);
+ yValues.Add(func(x0));
+ }
+
+ return new TabulateResult(xValues.ToArray(), yValues.ToArray());
+ }
+
+ ///
+ /// Проводит табулирование функции
+ ///
+ /// Начальное значение
+ /// Максимальное значение
+ /// Шаг
+ /// Табулируемая функции
+ /// Массив для значений X
+ /// Массив для значений Y
+ public static void TabulateFunction(double x0, double xk, double dx, Func func, out double[] xValuesArray, out double[] yValuesArray)
+ {
+ List xValues = new List();
+
+ List yValues = new List();
+
+ for (; x0 <= xk; x0 += dx)
+ {
+ xValues.Add(x0);
+ yValues.Add(func(x0));
+ }
+
+ xValuesArray = xValues.ToArray();
+
+ yValuesArray = yValues.ToArray();
+
+ }
+
+ }
}
diff --git a/MathExtendentTests/ExtendentRandomTests.cs b/MathExtendentTests/ExtendentRandomTests.cs
new file mode 100644
index 0000000..b4e6807
--- /dev/null
+++ b/MathExtendentTests/ExtendentRandomTests.cs
@@ -0,0 +1,47 @@
+using MathExtended;
+using System;
+using Xunit;
+
+namespace MathExtendedTests
+{
+ public class ExtendentRandomTests
+ {
+ [Theory]
+ [InlineData(1, 3)]
+ [InlineData(2, 3)]
+ [InlineData(-2, 0)]
+ [InlineData(-2, 3)]
+ public void ExtendentRandomGeneratesIntValueInRangeOfValues(int downBound, int upperBound)
+ {
+ int generatedValue = new ExtendentRandom().Next(downBound, upperBound);
+
+ Assert.True(generatedValue < upperBound && generatedValue >= downBound);
+ }
+
+ [Theory]
+ [InlineData(1, 3)]
+ [InlineData(2, 3)]
+ [InlineData(3.6, 3.7)]
+ [InlineData(2.666, 2.777)]
+ [InlineData(-3.6, 0)]
+ [InlineData(-3.1, -2)]
+ public void ExtendentRandomGeneratesDoubleValueInRangeOfValues(double downBound, double upperBound)
+ {
+ double generatedValue = new ExtendentRandom().Next(downBound, upperBound);
+
+ Assert.True(generatedValue < upperBound && generatedValue >= downBound);
+ }
+
+ [Theory]
+ [InlineData(4, 2)]
+ [InlineData(2, 0)]
+ [InlineData(-2, -4)]
+ public void ExtendentRandomGeneratesValueInInvalidRange(int downBound, int upperBound)
+ {
+ Assert.Throws(() => new ExtendentRandom().Next(downBound, upperBound));
+ }
+
+
+
+ }
+}
diff --git a/MathExtendentTests/MathExtendedTests.cs b/MathExtendentTests/MathExtendedTests.cs
new file mode 100644
index 0000000..ec7236b
--- /dev/null
+++ b/MathExtendentTests/MathExtendedTests.cs
@@ -0,0 +1,43 @@
+using MathExtended;
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+
+namespace MathExtendedTests
+{
+ public class MathExtendentTest
+ {
+ ///
+ /// y y
+ ///
+ [Fact]
+ public void TabulateFunctionReturnsSameArrays()
+ {
+ double[] factValues = { 64, 49, 36, 25, 16, 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64 };
+
+ IReadOnlyCollection calculatedValuesY;
+
+ Func function = (x) => x * x;
+
+ calculatedValuesY = MathExtendent.TabulateFunction(-8, 8, 1, function).Y;
+
+ Assert.Equal(factValues, calculatedValuesY);
+ }
+
+ ///
+ ///
+ ///
+ [Fact]
+ public void AlgebraicSumReturnsSameSum()
+ {
+ double factSum = 333835502;
+
+ double calculatedSum = MathExtendent.AlgebraicSum(0, 1000, (x) => Math.Pow(x, 2) + 2);
+
+ Assert.Equal(calculatedSum, factSum);
+ }
+
+
+ }
+}
diff --git a/MathExtendentTests/MathExtendentTests.csproj b/MathExtendentTests/MathExtendentTests.csproj
new file mode 100644
index 0000000..7a1c9d3
--- /dev/null
+++ b/MathExtendentTests/MathExtendentTests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/MathExtendentTests/Matrices/MatrixTests.cs b/MathExtendentTests/Matrices/MatrixTests.cs
new file mode 100644
index 0000000..797e946
--- /dev/null
+++ b/MathExtendentTests/Matrices/MatrixTests.cs
@@ -0,0 +1,183 @@
+using MathExtended.Exceptions;
+using MathExtended.Matrices;
+using MathExtended.Matrices.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace MathExtendedTests
+{
+ public class MatrixTests
+ {
+ [Theory]
+ [InlineData(1, 1)]
+ [InlineData(3, 3)]
+ [InlineData(3, 2)]
+ [InlineData(3, 6)]
+ public void InitMatrix(int rowsCount, int columnsCount)
+ {
+ Matrix matrix = new Matrix(rowsCount, columnsCount);
+
+ Assert.Equal(rowsCount, matrix.RowsCount);
+ Assert.Equal(columnsCount, matrix.ColumnsCount);
+ Assert.Equal(rowsCount * columnsCount, matrix.Size);
+ }
+
+ [Fact]
+ public void InitMatrixByFunc()
+ {
+ Func func = (r, c) => (r + 1) * (c + 1);
+
+ double[,] expected = { { 1, 2, 3 }, { 2, 4, 6 }, { 3, 6, 9 } };
+
+ Matrix matrix = new Matrix(3, 3).InitBy(func);
+
+ Assert.Equal(expected, (double[,])matrix);
+ }
+
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(0, 1)]
+ [InlineData(1, 0)]
+ [InlineData(-1, 1)]
+ [InlineData(1, -1)]
+ [InlineData(-1, -1)]
+ public void InitInvalidRowsAndColumnsCountMatrix(int rowsCount, int columnsCount)
+ {
+ Assert.Throws(() => new Matrix(rowsCount, columnsCount));
+ }
+
+ [Theory]
+ [InlineData(1, 1, 1)]
+ [InlineData(3, 3, 9)]
+ [InlineData(3, 2, 6)]
+ [InlineData(3, 6, 18)]
+ public void ForEachInMatrix(int rowsCount, int columnsCount, int eventInvokeCount)
+ {
+ int eventInvokeCountActual = 0;
+
+ Matrix matrix = new Matrix(rowsCount, columnsCount);
+
+ matrix.ForEach((cell) => eventInvokeCountActual++);
+
+ Assert.Equal(eventInvokeCount, eventInvokeCountActual);
+ }
+
+ [Theory]
+ [InlineData(3, 3, new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })]
+ [InlineData(3, 2, new double[] { 1, 2, 3, 4, 5, 6 })]
+ [InlineData(2, 3, new double[] { 1, 2, 3, 4, 5, 6 })]
+ public void FillInOrderAllMatrixCellls(int rowsCount, int columnsCount, IEnumerable expectedValues)
+ {
+ Matrix matrix = new Matrix(rowsCount, columnsCount).FillInOrder();
+
+ Assert.Equal(expectedValues, matrix);
+
+ }
+
+ [Theory]
+ [InlineData(3, 3, new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18 })]
+ [InlineData(3, 2, new int[] { 2, 4, 6, 8, 10, 12 })]
+ [InlineData(2, 3, new int[] { 2, 4, 6, 8, 10, 12 })]
+ public void AddOperatorMatrix(int rowsCount, int columnsCount, ICollection expectedValues)
+ {
+ List actualValues = new List();
+
+ Matrix matrixA = new Matrix(rowsCount, columnsCount).FillInOrder();
+
+ Matrix matrixB = new Matrix(rowsCount, columnsCount).FillInOrder();
+
+ Matrix matrixС = matrixA + matrixB;
+
+ matrixС.ForEach((cell) => actualValues.Add(cell));
+
+ Assert.Equal(expectedValues, actualValues);
+
+ }
+
+ [Theory]
+ [InlineData(3, 2, 2, 3)]
+ [InlineData(2, 3, 3, 2)]
+ public void AddOperatorMatricesDifferentSizes(int rowsCountFirstMatrix, int columnsCountFirstMatrix, int rowsCountSecondMatrix, int columnsCountSecondMatrix)
+ {
+ Matrix matrixA = new Matrix(rowsCountFirstMatrix, columnsCountFirstMatrix).FillInOrder();
+
+ Matrix matrixB = new Matrix(rowsCountSecondMatrix, columnsCountSecondMatrix).FillInOrder();
+
+ Assert.Throws(() => matrixA + matrixB);
+
+ }
+
+ [Theory]
+ [InlineData(3, 3, 3, 3)]
+ [InlineData(3, 2, 3, 2)]
+ [InlineData(3, 6, 3, 6)]
+ public void MinusOperatorMatrices
+ (int rowsCountFirstMatrix, int columnsCountFirstMatrix, int rowsCountSecondMatrix, int columnsCountSecondMatrix)
+ {
+ Matrix matrixA = new Matrix(rowsCountFirstMatrix, columnsCountFirstMatrix).FillInOrder();
+
+ Matrix matrixB = new Matrix(rowsCountSecondMatrix, columnsCountSecondMatrix).FillInOrder();
+
+ Matrix result = matrixA - matrixB;
+
+ result.ToList().ForEach(c => Assert.Equal(0, c));
+ }
+
+ [Theory]
+ [InlineData(3, 2, 2, 3)]
+ [InlineData(2, 3, 3, 2)]
+ public void MinusOperatorMatricesDifferentSizes(int rowsCountFirstMatrix, int columnsCountFirstMatrix, int rowsCountSecondMatrix, int columnsCountSecondMatrix)
+ {
+ Matrix matrixA = new Matrix(rowsCountFirstMatrix, columnsCountFirstMatrix).FillInOrder();
+
+ Matrix matrixB = new Matrix(rowsCountSecondMatrix, columnsCountSecondMatrix).FillInOrder();
+
+ Assert.Throws(() => matrixA + matrixB);
+ }
+
+ [Theory]
+ [InlineData(3, 3, 3, 3, new double[] { 30, 36, 42, 66, 81, 96, 102, 126, 150 })]
+ [InlineData(4, 4, 4, 4, new double[] { 90, 100, 110, 120, 202, 228, 254, 280, 314, 356, 398, 440, 426, 484, 542, 600 })]
+ [InlineData(4, 3, 3, 4, new double[] { 38, 44, 50, 56, 83, 98, 113, 128, 128, 152, 176, 200, 173, 206, 239, 272 })]
+ [InlineData(2, 3, 3, 2, new double[] { 22, 28, 49, 64 })]
+ public void MultiplyOperatorMatricesDifferentSizes(int rowsCountFirstMatrix, int columnsCountFirstMatrix, int rowCountSecondMatrix, int columnsCountSecondMatrix, ICollection expected)
+ {
+ Matrix matrixA = new Matrix(rowsCountFirstMatrix, columnsCountFirstMatrix).FillInOrder();
+
+ Matrix matrixB = new Matrix(rowCountSecondMatrix, columnsCountSecondMatrix).FillInOrder();
+
+ Matrix result = matrixA * matrixB;
+
+ Assert.Equal(expected, result);
+
+ }
+
+ [Theory]
+ [InlineData(3, 2, 4, 2)]
+ [InlineData(4, 2, 3, 2)]
+ public void MultiplyOperatorInvalidSizes(int rowsCountFirstMatrix, int columnsCountFirstMatrix, int rowCountSecondMatrix, int columnsCountSecondMatrix)
+ {
+ Matrix matrixA = new Matrix(rowsCountFirstMatrix, columnsCountFirstMatrix);
+
+ Matrix matrixB = new Matrix(rowCountSecondMatrix, columnsCountSecondMatrix);
+
+ Assert.Throws(() => matrixA * matrixB);
+ }
+
+ [Theory]
+ [InlineData(3, 3, new double[] { 1, 4, 7, 2, 5, 8, 3, 6, 9 })]
+ [InlineData(3, 2, new double[] { 1, 3, 5, 2, 4, 6 })]
+ [InlineData(2, 3, new double[] { 1, 4, 2, 5, 3, 6 })]
+ public void TransponateMatrixDifferentSizes(int rowsCount, int columsCount, ICollection expected)
+ {
+ Matrix matrix = new Matrix(rowsCount, columsCount)
+ .FillInOrder()
+ .Transponate();
+
+ Assert.Equal(expected, matrix);
+ }
+
+ }
+}
diff --git a/Matrices/BaseMatrix.cs b/Matrices/BaseMatrix.cs
new file mode 100644
index 0000000..1a98f1a
--- /dev/null
+++ b/Matrices/BaseMatrix.cs
@@ -0,0 +1,468 @@
+using MathExtended.Exceptions;
+using MathExtended.Interfaces;
+using MathExtended.Matrices.Extensions;
+using MathExtended.Matrices.Structures.CellsCollection;
+using MathExtended.Matrices.Structures.CellsCollections;
+using MathExtended.Matrices.Structures.Columns;
+using MathExtended.Matrices.Structures.Rows;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MathExtended.Matrices
+{
+ ///
+ /// Базовый класс матрицы.Реализует интерфейс перечисления
+ /// и ограничивает принимаемые обобщения до числовых типов (, , и т.д)
+ ///
+ /// Числовой тип
+ public abstract class BaseMatrix : IEnumerable, IEnumerator, IMatrix where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ ///
+ /// Матрица представляющая собой двумерный массив
+ ///
+ protected T[,] matrix;
+
+ private Row[] _rows;
+
+ private Column[] _columns;
+
+ private int _rowsCount;
+
+ private int _columnsCount;
+
+ ///
+ /// Главная диагональ
+ ///
+ protected MainDiagonal _mainDiagonal;
+
+ private int _rowPosition = 0;
+
+ private int _columnPosition = -1;
+
+ private bool disposedValue;
+
+
+ ///
+ /// Создает матрицу с указанными размерами
+ ///
+ /// Количество строк
+ /// Количество столбцов
+ public BaseMatrix(int rows, int columns)
+ {
+ if (!(rows <= 0) && !(columns <= 0))
+ {
+ _rowsCount = rows;
+
+ _columnsCount = columns;
+
+ matrix = new T[rows, columns];
+
+ _rows = GetRows();
+
+ _columns = GetColumns();
+ }
+ else
+ {
+ throw new MatrixInvalidSizesException();
+ }
+ }
+
+ ///
+ /// Число матрицы
+ ///
+ /// Строка
+ /// Столбец
+ /// Число по указанному адресу в матрице
+ public T this[int row, int column]
+ {
+ get => matrix[row, column];
+
+ set
+ {
+ matrix[row, column] = value;
+ }
+
+ }
+
+ ///
+ /// Колличество строк в матрице
+ ///
+ public int RowsCount
+ {
+ get => _rowsCount;
+ }
+
+ ///
+ /// Колличество столбцов в матрице
+ ///
+ public int ColumnsCount
+ {
+ get => _columnsCount;
+ }
+
+ ///
+ /// Главная диагональ
+ ///
+ public MainDiagonal MainDiagonal
+ {
+ get
+ {
+ _mainDiagonal = this.FindDiagonal();
+ return _mainDiagonal;
+ }
+
+ protected set
+ {
+ _mainDiagonal = value;
+ }
+ }
+
+ ///
+ /// Возвращает столбец или строку в
+ /// зависимости от селектора
+ ///
+ /// Селектор векторов
+ /// Индекс вектора
+ /// Вектор или строка по индексу
+ protected virtual BaseReadOnlyCellsCollection this[VectorSelector selector, int index]
+ {
+ get
+ {
+ if (selector == VectorSelector.Rows)
+ {
+ return (ReadOnlyRow)_rows[index];
+ }
+ else
+ {
+ return (ReadOnlyColumn)_columns[index];
+ }
+ }
+
+ }
+
+ ///
+ /// Возвращает стоки или столбцы в зависимости от селектора
+ ///
+ /// Селектор
+ /// Массив строк или столбцов
+ public virtual BaseCellsCollection[] this[VectorSelector selector]
+ {
+ get
+ {
+ if (selector == VectorSelector.Rows)
+ {
+ return _rows;
+ }
+ else
+ {
+ return _columns;
+ }
+ }
+
+ }
+
+
+ ///
+ /// Возвращает строку матрицы соответсвующую индексу
+ ///
+ /// Индекс строки
+ /// строка матрицы
+ public Row GetRow(int rowIndex)
+ {
+ if (rowIndex < RowsCount)
+ {
+ var fullRow = new List();
+
+ for (int column = 0; column < ColumnsCount; column++)
+ {
+ fullRow.Add(this[rowIndex, column]);
+ }
+
+
+ return new Row(fullRow.ToArray());
+ }
+ else
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+
+ }
+
+ ///
+ /// Возвращает все строки матрицы
+ ///
+ /// Массив из
+ public Row[] GetRows()
+ {
+ Row[] rows = new Row[RowsCount];
+
+ for (int row = 0; row < RowsCount; row++)
+ {
+ rows[row] = GetRow(row);
+ }
+
+ return rows;
+ }
+
+ ///
+ /// Задает строку матрицы по заданному индексу
+ ///
+ /// Строка
+ /// Индекс строки
+ public void SetRow(Row row, int index)
+ {
+ if (index <= row.Size)
+ {
+
+ ForEach((r, c) => this[index, c] = row[c]);
+
+ }
+ else
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+ }
+
+ ///
+ /// Задает строки матрицы
+ ///
+ /// Строки
+ public void SetRows(Row[] rows)
+ {
+ ForEach((row, column) =>
+ {
+ if (row <= rows.Length - 1)
+ {
+ this[row, column] = rows[row][column];
+ }
+ });
+ }
+
+ ///
+ /// Возвращает столбец матрицы по индексу
+ ///
+ /// Индекс столбца
+ ///
+ public Column GetColumn(int columnIndex)
+ {
+ if (columnIndex < ColumnsCount)
+ {
+ var fullColumn = new List();
+
+ for (int column = 0; column < RowsCount; column++)
+ {
+ fullColumn.Add(this[column, columnIndex]);
+ }
+
+ return (Column)fullColumn.ToArray();
+ }
+ else
+ {
+ throw new IndexOutOfRangeException($"Index {columnIndex} out of the bounds matrix");
+ }
+
+ }
+
+ ///
+ /// Возвращает все столбцы матрицы
+ ///
+ /// Массив
+ public Column[] GetColumns()
+ {
+ Column[] columns = new Column[ColumnsCount];
+
+ ForEach((row, column) => columns[column] = GetColumn(column));
+
+ return columns;
+ }
+
+ ///
+ /// Задает столбец матрицы по индексу
+ ///
+ /// Индекс столбца
+ /// Стобец
+ public void SetColumn(int columnIndex, Column column)
+ {
+ if (columnIndex <= this.RowsCount - 1)
+ {
+ ForEach((r, c) => this[r, columnIndex] = column[r]);
+
+ }
+ else
+ {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+
+ ///
+ /// Задает столбцы матрицы
+ ///
+ /// Столбцы
+ public void SetColumns(Column[] columns)
+ {
+ ForEach((row, column) => SetColumn(row, columns[row]));
+ }
+
+ ///
+ /// Применяет функцию ко всем элементам матрицы
+ ///
+ /// Делегат с одним параметром
+ protected private void ForEach(Action action)
+ {
+
+ if (action == null)
+ {
+ throw new ArgumentNullException();
+ }
+ else
+ {
+ Parallel.For(0, this.RowsCount, row =>
+ {
+ for (dynamic column = 0; column < this.ColumnsCount; column++)
+ {
+ action(row, column);
+ }
+ });
+ }
+
+ }
+
+ ///
+ /// Преобразует матрицу в двумерный массив
+ ///
+ /// Двумерный массив
+ public static explicit operator T[,](BaseMatrix matrix)
+ {
+ return matrix.matrix;
+ }
+
+
+
+ #region IEnumerable
+ ///
+ /// Текуший элемент
+ ///
+ public T Current
+ {
+ get
+ {
+ return matrix[_rowPosition, _columnPosition];
+ }
+ }
+
+ object IEnumerator.Current => Current;
+
+
+
+ ///
+ /// Перечислитель
+ ///
+ /// Перечислитель матрицы
+ public IEnumerator GetEnumerator()
+ {
+ foreach (var i in matrix)
+ {
+
+ yield return i;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+
+
+ ///
+ /// Перемещает индексатор на одну позицию вперед
+ ///
+ /// true или false в зависимости ли можно переместить индексатор
+ public bool MoveNext()
+ {
+
+ if (_rowPosition < this.RowsCount)
+ {
+ if (_columnPosition < this.ColumnsCount - 1)
+ {
+ _columnPosition++;
+ }
+ else
+ {
+ if (_rowPosition < this.RowsCount - 1)
+ {
+ _rowPosition++;
+ }
+ else
+ {
+ return false;
+ }
+ _columnPosition = 0;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+
+
+ }
+
+ ///
+ /// Перемещает индексатор в начало матрицы
+ ///
+ public void Reset()
+ {
+ _rowPosition = 0;
+ _columnPosition = -1;
+ }
+
+
+
+ ///
+ /// Высвобождает использованные ресурсы
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+
+ matrix = null;
+ MainDiagonal = null;
+ }
+
+ // TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения
+ // TODO: установить значение NULL для больших полей
+ disposedValue = true;
+ }
+ }
+
+ // // TODO: переопределить метод завершения, только если "Dispose(bool disposing)" содержит код для освобождения неуправляемых ресурсов
+ // ~Matrix()
+ // {
+ // // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)".
+ // Dispose(disposing: false);
+ // }
+
+ ///
+ /// Освобождает использованные ресурсы
+ ///
+ public void Dispose()
+ {
+ // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)".
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
diff --git a/Matrices/Extensions/MatrixExtensions.cs b/Matrices/Extensions/MatrixExtensions.cs
new file mode 100644
index 0000000..4a25d49
--- /dev/null
+++ b/Matrices/Extensions/MatrixExtensions.cs
@@ -0,0 +1,202 @@
+using MathExtended.Interfaces;
+using MathExtended.Matrices.Structures.CellsCollections;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+
+namespace MathExtended.Matrices.Extensions
+{
+ ///
+ /// Класс расширений для объектов
+ ///
+ public static class MatrixExtensions
+ {
+ ///
+ /// Выполняет действие с кaждой ячейкой матрицы
+ ///
+ /// Матрица
+ /// Действие
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ForEach(this IMatrix matrix, Action action) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ foreach (var cell in matrix)
+ {
+ action(cell);
+ }
+ }
+ private static void ForEach(this IMatrix matrix, Action action) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException();
+ }
+ else
+ {
+ for (dynamic row = 0; row < matrix.RowsCount; row++)
+ {
+ for (dynamic column = 0; column < matrix.ColumnsCount; column++)
+ {
+ action(row, column);
+ }
+ }
+ }
+
+ }
+
+ public static void ForEachAsParrallel(this IMatrix matrix, Action action) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Parallel.For(0, matrix.RowsCount, row =>
+ {
+ Parallel.For(0, matrix.ColumnsCount, column =>
+ {
+ action.Invoke(row, column);
+ });
+ });
+ }
+
+ ///
+ /// Находит главную диагональ матрицы
+ ///
+ /// Тип ячеек матрицы
+ /// Матрица
+ /// Главна диагональ
+ public static MainDiagonal FindDiagonal(this IMatrix matrix) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ List mainDiagonal = new List();
+
+ ForEach(matrix, (row, column) =>
+ {
+ if (row == column)
+ {
+ mainDiagonal.Add(matrix[row, column]);
+ }
+
+ });
+
+ return new MainDiagonal(mainDiagonal.ToArray());
+ }
+
+ ///
+ /// Транспонирует(меняет строки со столбцами) текущую матрицу и возвращает новую
+ ///
+ /// Транспонированная матрица
+ public static Matrix Transponate(this IMatrix matrix) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Matrix transposedMatrix = new Matrix(matrix.ColumnsCount, matrix.RowsCount);
+
+ transposedMatrix.ForEachAsParrallel((r,c) => transposedMatrix[r, c] = matrix[c,r]);
+
+ return transposedMatrix;
+ }
+
+ ///
+ /// Initialize matrix by function
+ /// matrix cell value will be equal to function(Method) result.
+ /// Arguments for function - cells indexes
+ ///
+ /// Numerical type
+ /// Matrix
+ /// Function
+ /// Initialized matrix
+ public static Matrix InitBy(this IMatrix matrix, Func func) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Matrix initedMatrix = new Matrix(matrix.RowsCount, matrix.ColumnsCount);
+
+ matrix.ForEach((r, c) => initedMatrix[r, c] = func.Invoke((dynamic)r, (dynamic)c));
+
+ return initedMatrix;
+ }
+
+ ///
+ /// Заполняет матрицу по порядку:от 1-го до размера последнего элемента матрицы
+ ///
+ /// Матрица заполненная по порядку
+ public static Matrix FillInOrder(this IMatrix matrix) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Matrix filledMatrix = new Matrix(matrix.RowsCount, matrix.ColumnsCount);
+
+ dynamic counter = 1;
+
+ matrix.ForEach((row, column) => filledMatrix[row, column] = counter++);
+
+ return filledMatrix;
+ }
+
+
+ ///
+ /// Заполняет матрицу случайными целочисленными значениями
+ ///
+ /// Матрица со случайными значениями
+ public static Matrix FillRandom(this IMatrix matrix) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Matrix filledMatrix = new Matrix(matrix.RowsCount, matrix.ColumnsCount);
+
+ ExtendentRandom random = new ExtendentRandom();
+
+ Parallel.For(0, matrix.RowsCount, row =>
+ {
+ Parallel.For(0, matrix.ColumnsCount, column =>
+ {
+ filledMatrix[row, column] = random.Next();
+ });
+ });
+
+ return filledMatrix;
+ }
+
+ ///
+ /// Заполняет матрицу случайными значениями в определенном диапазоне
+ ///
+ /// Матрица
+ /// Минимальное число
+ /// Максимальное число
+ /// Матрица со случайными значениями
+ public static Matrix FillRandom(this IMatrix matrix, T min, T max) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ Matrix filledMatrix = new Matrix(matrix.RowsCount, matrix.ColumnsCount);
+
+ ExtendentRandom random = new ExtendentRandom();
+
+ Parallel.For(0, matrix.RowsCount, row =>
+ {
+ Parallel.For(0, matrix.ColumnsCount, column =>
+ {
+
+ filledMatrix[row, column] = random.Next(min, max);
+
+ });
+ });
+
+ return filledMatrix;
+ }
+
+ ///
+ /// Находит минор матрицы
+ ///
+ /// Матрица
+ /// Вычеркнутая строка
+ /// Вычеркнутый столбец
+ /// Минор матрицы
+ public static Matrix FindMinor(this IMatrix matrix, uint crossedOutRow, uint crossedOutColumn) where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ int i, j, p, q;
+
+ Matrix minor = new Matrix(matrix.RowsCount - 1, matrix.ColumnsCount - 1);
+
+ for (j = 0, q = 0; q < minor.RowsCount; j++, q++)
+ {
+ for (i = 0, p = 0; p < minor.ColumnsCount; i++, p++)
+ {
+ if (i == crossedOutRow) i++;
+ if (j == crossedOutColumn) j++;
+ minor[p, q] = matrix[i, j];
+ }
+
+ }
+
+ return minor;
+ }
+ }
+}
diff --git a/Matrices/Matrix.cs b/Matrices/Matrix.cs
new file mode 100644
index 0000000..64289d7
--- /dev/null
+++ b/Matrices/Matrix.cs
@@ -0,0 +1,428 @@
+using MathExtended.Exceptions;
+using MathExtended.Matrices.Structures.CellsCollections;
+using MiscUtil;
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+namespace MathExtended.Matrices
+{
+ ///
+ /// Описывает основную логику матриц
+ ///
+ /// Числовой тип
+ public class Matrix : BaseMatrix where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ #region Поля матрицы
+
+ private bool isSquareMatrix;
+
+ #endregion
+
+ private readonly double precalculatedDeterminant = double.NaN;
+
+ #region Свойства матрицы
+ ///
+ /// Размер матрицы
+ ///
+ public int Size
+ {
+ get => matrix.Length;
+ }
+
+ ///
+ /// Квадратность матрицы
+ ///
+ public bool IsSquareMatrix
+ {
+ get => isSquareMatrix;
+
+ private set
+ {
+ isSquareMatrix = base.RowsCount == base.ColumnsCount;
+ }
+ }
+
+
+ #endregion
+
+ ///
+ /// Создает матрицу с указанными размерами
+ ///
+ /// Колличество строк в матрице
+ /// Колличество столбцов матрице
+ public Matrix(int rows, int columns) : base(rows, columns)
+ {
+
+
+ IsSquareMatrix = RowsCount == ColumnsCount;
+
+ }
+
+ ///
+ /// Создает матрицу на основе двумерного массива
+ ///
+ /// Двумерный массив
+ public Matrix(T[,] array) : base(array.GetUpperBound(0) + 1, array.GetUpperBound(1) + 1)
+ {
+ matrix = array;
+
+ IsSquareMatrix = RowsCount == ColumnsCount;
+
+ }
+
+ #region Операторы
+
+ ///
+ /// Суммирует две матрицы
+ ///
+ ///
+ ///
+ /// Сумма A и B
+ public static Matrix operator +(Matrix matrixA, Matrix matrixB)
+ {
+ if (matrixA.ColumnsCount == matrixB.ColumnsCount && matrixA.RowsCount == matrixB.RowsCount)
+ {
+ var matrixC = new Matrix(matrixA.RowsCount, matrixB.ColumnsCount);
+
+
+ Parallel.For(0, matrixA.RowsCount, row =>
+ {
+ Parallel.For(0, matrixB.ColumnsCount, colunm =>
+ {
+ matrixC[row, colunm] = (T)(dynamic)matrixA[row, colunm] + (dynamic)matrixB[row, colunm];
+ });
+ });
+ return matrixC;
+ }
+ else
+ {
+ throw new MatrixDifferentSizeException();
+ }
+ }
+
+ ///
+ /// Разность матриц
+ ///
+ ///
+ ///
+ /// Разность матриц
+ public static Matrix operator -(Matrix matrixA, Matrix matrixB)
+ {
+ if (matrixA.ColumnsCount == matrixB.ColumnsCount && matrixA.RowsCount == matrixB.RowsCount)
+ {
+ var matrixC = new Matrix(matrixA.RowsCount, matrixB.ColumnsCount);
+
+ Parallel.For(0, matrixA.RowsCount, i =>
+ {
+
+ Parallel.For(0, matrixB.ColumnsCount, j =>
+ {
+ matrixC[i, j] = (T)Operator.Subtract(matrixA[i, j], matrixB[i, j]);
+ });
+
+ });
+
+ return matrixC;
+ }
+ else
+ {
+ throw new MatrixDifferentSizeException();
+ }
+
+ }
+
+ ///
+ /// Умножает матрицу на число
+ ///
+ ///
+ ///
+ /// Умноженная на число матрица
+ public static Matrix operator *(T multiplier, Matrix matrixA)
+ {
+ var matrixB = new Matrix(matrixA.RowsCount, matrixA.ColumnsCount);
+
+ Parallel.For(0, matrixA.RowsCount, row =>
+ {
+ Parallel.For(0, matrixA.ColumnsCount, column =>
+ {
+ matrixB[row, column] = (T)Operator.Multiply(matrixA[row, column], multiplier);
+ });
+
+ });
+
+ return matrixB;
+ }
+
+ ///
+ /// Умножает матрицу на число
+ ///
+ ///
+ ///
+ /// Умноженная на число матрица
+ public static Matrix operator *(Matrix matrixA, T multiplier)
+ {
+ return multiplier * matrixA;
+ }
+
+ ///
+ /// Перемножает матрицы
+ ///
+ ///
+ ///
+ ///
+ public static Matrix operator *(Matrix matrixA, Matrix matrixB)
+ {
+ if (matrixA.RowsCount == matrixB.ColumnsCount)
+ {
+ var matrixC = new Matrix(matrixA.RowsCount, matrixB.ColumnsCount);
+
+ Parallel.For(0, matrixA.RowsCount, row =>
+ {
+ Parallel.For(0, matrixB.ColumnsCount, column =>
+ {
+ for (int k = 0; k < matrixB.RowsCount; k++)
+ {
+ matrixC[row, column] = (T)Operator.Add(matrixC[row, column], Operator.Multiply(matrixA[row, k], matrixB[k, column]));
+ }
+ });
+ });
+
+ return matrixC;
+ }
+ else
+ {
+ throw new TheNumberOfRowsAndColumnsIsDifferentException();
+ }
+
+
+ }
+
+ ///
+ /// Явно приводит двумерный массив к
+ ///
+ /// Приводимый массив
+ public static explicit operator Matrix(T[,] array)
+ {
+ return new Matrix(array);
+ }
+
+ ///
+ /// Явно приводит к двумерному массиву
+ ///
+ /// Приводимая матрица
+ public static explicit operator T[,](Matrix matrix)
+ {
+ return matrix.matrix;
+ }
+
+
+ #endregion
+ private async Task FindRankAsync()
+ {
+ return await Task.Run(FindRank);
+ }
+
+ ///
+ /// Находит ранг мартицы
+ ///
+ /// Ранг матрицы
+ public int FindRank()
+ {
+ int rank = 0;
+
+ Parallel.ForEach(this.ToSteppedView()[VectorSelector.Rows], row =>
+ {
+ if (!row.IsZero())
+ {
+ rank++;
+ }
+ });
+
+ return rank;
+ }
+
+ ///
+ /// Возводит матрицу в степень
+ ///
+ /// Матрица
+ /// Степень
+ /// Матрица в заданной степени
+ public static Matrix Pow(Matrix matrix, int power)
+ {
+
+ if (matrix != null && matrix.ColumnsCount == matrix.RowsCount)
+ {
+ var matrixC = matrix;
+
+ for (int i = 1; i <= power; i++)
+ {
+ matrixC *= matrix;
+ }
+ return matrixC;
+ }
+ else
+ {
+ throw new TheNumberOfRowsAndColumnsIsDifferentException();
+ }
+
+ }
+
+ ///
+ /// Приводит матрицу к ступенчатому виду
+ ///
+ /// Матрица в ступенчатов виде
+ public Matrix ToSteppedView()
+ {
+ var steppedMatrix = this;
+
+ steppedMatrix.ForEach((row, column) =>
+ {
+
+ for (int j = row + 1; j < steppedMatrix.RowsCount; j++)
+ {
+
+ if (this[row, row] != (dynamic)0)
+ {
+
+ if (this[row, row] != (dynamic)0)
+ {
+ dynamic koeficient = (dynamic)(steppedMatrix[j, row] / (dynamic)this[row, row]);
+
+ for (int k = 0; k < steppedMatrix.ColumnsCount; k++)
+ {
+
+ steppedMatrix[j, k] -= steppedMatrix[row, k] * koeficient;
+
+ }
+ }
+ }
+ }
+ });
+
+
+ return steppedMatrix;
+ }
+
+ ///
+ /// Создает матрицу с вычеркнутыми столбцами на основе текущей
+ ///
+ /// Количество вычеркнутых столбцов
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix CreateMatrixWithoutColumn(int column)
+ {
+ if (column < 0 || column >= this.ColumnsCount)
+ {
+ throw new ArgumentException("invalid column index");
+ }
+ var result = new Matrix(this.RowsCount, this.ColumnsCount - 1);
+ result.ForEach((i, j) =>
+ result[i, j] =
+ j < column ? this[i, j] : this[i, j + 1]);
+ return result;
+ }
+
+ ///
+ /// Создает матрицу с вычеркнутыми строками на основе текущей
+ ///
+ /// Количество вычеркнутых строк
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix CreateMatrixWithoutRow(int row)
+ {
+ if (row < 0 || row >= this.RowsCount)
+ {
+ throw new ArgumentException("invalid row index");
+ }
+ var result = new Matrix(this.RowsCount - 1, this.ColumnsCount);
+ result.ForEach((i, j) =>
+ result[i, j] =
+ i < row ?
+ this[i, j] : this[i + 1, j]);
+ return result;
+ }
+
+ ///
+ /// Расчитывает детерминант матрицы
+ ///
+ /// Детерминант матрицы
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T CalculateDeterminant()
+ {
+ dynamic result = 0;
+
+ if (!double.IsNaN(this.precalculatedDeterminant))
+ {
+ return Operator.Convert(this.precalculatedDeterminant);
+ }
+
+ if (!this.IsSquareMatrix)
+ {
+ throw new InvalidOperationException("determinant can be calculated only for square matrix");
+ }
+
+ if (this.RowsCount == 2)
+ {
+ return Operator.Subtract(Operator.Multiply(this[0, 0], this[1, 1]), Operator.Multiply(this[0, 1], this[1, 0]));
+ }
+
+ if (this.RowsCount == 1)
+ {
+ return this[0, 0];
+ }
+
+
+ for (var j = 0; j < this.RowsCount; j++)
+ {
+ result += Operator.Multiply(Operator.Multiply((j % 2 == 1 ? (dynamic)1 : -(dynamic)1), this[1, j]),
+ this.CreateMatrixWithoutColumn(j).CreateMatrixWithoutRow(1).CalculateDeterminant());
+
+ }
+
+ return result;
+
+ }
+
+ ///
+ /// Расчитывает детерминант матрицы асинхронно
+ ///
+ /// Детерминант матрицы
+ public async Task CalculateDeterminantAsync()
+ {
+ return await Task.Run(CalculateDeterminant);
+ }
+
+ #region Features
+
+ ///
+ /// Вывод матрицы в строковом представлении
+ ///
+ /// Строковое представление матрицы
+ public override string ToString()
+ {
+ string outString = String.Empty;
+
+ for (int row = 0; row < this.RowsCount; row++)
+ {
+ for (int column = 0; column < this.ColumnsCount; column++)
+ {
+ outString += matrix[row, column].ToString().PadLeft(8) + " ";
+
+ }
+
+ outString += "\n";
+ };
+
+
+
+ return outString;
+ }
+
+
+
+ #endregion
+
+
+ }
+}
diff --git a/Matrices/Structures/CellsCollections/BaseCellsCollection.cs b/Matrices/Structures/CellsCollections/BaseCellsCollection.cs
new file mode 100644
index 0000000..443f71b
--- /dev/null
+++ b/Matrices/Structures/CellsCollections/BaseCellsCollection.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MathExtended.Matrices.Structures.CellsCollection
+{
+ ///
+ /// Описывает коллекцию ячеек
+ ///
+ /// Числовой тип
+ public class BaseCellsCollection : IEnumerator, IEnumerable where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ private T[] _cells;
+ private int _size;
+ private bool disposedValue;
+ private int _position;
+
+ ///
+ /// Индексатор.По индексу возвращает или задает значение ячейки
+ ///
+ /// Индекс элемента
+ /// Элемент по индексу
+ public virtual T this[int index]
+ {
+ get
+ {
+ return _cells[index];
+ }
+
+ set
+ {
+ _cells[index] = value;
+ }
+ }
+
+ ///
+ /// Массив ячеек
+ ///
+ protected virtual T[] Cells
+ {
+ get => _cells;
+
+ set
+ {
+ _cells = value;
+ }
+ }
+
+
+ ///
+ /// Размер коллекции
+ ///
+ public int Size
+ {
+ get => _cells.Length;
+ }
+
+ ///
+ /// Создает коллекцию с указанным размером
+ ///
+ /// Размер коллекции
+ public BaseCellsCollection(int size)
+ {
+ _cells = new T[size];
+ }
+
+ ///
+ /// Создает коллекцию ячеек на основе массива
+ ///
+ /// Входной массив
+ public BaseCellsCollection(T[] array)
+ {
+ _cells = array;
+ _size = array.Length;
+ }
+
+
+ ///
+ /// Применяет действие ко всем элементам
+ ///
+ /// Действие
+ public virtual void ForEach(Action action)
+ {
+ foreach (T cell in _cells)
+ {
+ action(cell);
+ }
+ }
+
+ ///
+ /// Находит максимальное число среди ячеек
+ ///
+ /// Максимальное значение в последовательности ячеек
+ public virtual T Max() => _cells.Max();
+
+
+ ///
+ /// Находит минимальное число среди ячеек
+ ///
+ /// Минимальное значение в последовательности ячеек
+ public virtual T Min() => _cells.Min();
+
+ ///
+ /// Проверяет нулевая ли коллекция
+ ///
+ /// - если все ячейки равны нулю, - если хоть одна ячейка не равна нулю
+ public virtual bool IsZero()
+ {
+ return _cells.All((cell) => cell == (dynamic)0);
+ }
+
+
+ #region IEnumerable
+ ///
+ /// Текуший элемент
+ ///
+ public T Current
+ {
+ get
+ {
+ return _cells[_position];
+ }
+ }
+
+ object IEnumerator.Current => Current;
+
+ ///
+ /// Перечислитель
+ ///
+ /// Перечислитель матрицы
+ public IEnumerator GetEnumerator()
+ {
+ foreach (var i in _cells)
+ {
+
+ yield return i;
+ }
+ }
+
+ ///
+ /// Перемещает индексатор на одну позицию вперед
+ ///
+ /// true или false в зависимости ли можно переместить индексатор
+ public bool MoveNext()
+ {
+
+ if (_position < this.Size - 1)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+
+
+ }
+
+ ///
+ /// Перемещает индексатор в начало матрицы
+ ///
+ public void Reset()
+ {
+ _position = -1;
+ }
+
+ ///
+ /// Высвобождает использованные ресурсы
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+ _cells = null;
+ }
+
+ // TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения
+ // TODO: установить значение NULL для больших полей
+ disposedValue = true;
+ }
+ }
+
+ // // TODO: переопределить метод завершения, только если "Dispose(bool disposing)" содержит код для освобождения неуправляемых ресурсов
+ // ~Matrix()
+ // {
+ // // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)".
+ // Dispose(disposing: false);
+ // }
+
+ ///
+ /// Освобождает использованные ресурсы
+ ///
+ public void Dispose()
+ {
+ // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)".
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _cells.GetEnumerator();
+ }
+
+ #endregion
+ }
+}
diff --git a/Matrices/Structures/CellsCollections/BaseReadOnlyCellsCollection.cs b/Matrices/Structures/CellsCollections/BaseReadOnlyCellsCollection.cs
new file mode 100644
index 0000000..70d7c0e
--- /dev/null
+++ b/Matrices/Structures/CellsCollections/BaseReadOnlyCellsCollection.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace MathExtended.Matrices.Structures.CellsCollection
+{
+ ///
+ /// Описывает коллекцию ячеек только для чтения
+ ///
+ /// Числовой тип
+ public abstract class BaseReadOnlyCellsCollection : BaseCellsCollection where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+
+ ///
+ /// Создает коллекцию ячеек только для чтения с указанным размером
+ ///
+ /// Размер коллеции
+ public BaseReadOnlyCellsCollection(int size) : base(size)
+ {
+ Cells = new T[size];
+ }
+
+ ///
+ /// Создает коллецию только для чтения на основе массива
+ ///
+ /// Массив
+ public BaseReadOnlyCellsCollection(T[] array) : base(array)
+ {
+ Cells = array;
+ }
+
+ ///
+ /// Индексатор.По индексу возвращает или задает значение ячейки
+ ///
+ /// Индекс элемента
+ /// Элемент по индексу
+ public override T this[int index]
+ {
+ get => base[index];
+ }
+ }
+}
diff --git a/Matrices/Structures/CellsCollections/MainDiagonal.cs b/Matrices/Structures/CellsCollections/MainDiagonal.cs
new file mode 100644
index 0000000..a9b1c4c
--- /dev/null
+++ b/Matrices/Structures/CellsCollections/MainDiagonal.cs
@@ -0,0 +1,22 @@
+using MathExtended.Matrices.Structures.CellsCollection;
+using System;
+
+namespace MathExtended.Matrices.Structures.CellsCollections
+{
+ ///
+ /// Описывает главную диагональ матрицы
+ ///
+ /// Числовой тип
+ public class MainDiagonal : BaseReadOnlyCellsCollection where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ ///
+ /// Создает клавную диагональ на основе массива
+ ///
+ /// Массив
+ public MainDiagonal(T[] array) : base(array)
+ {
+
+ }
+
+ }
+}
diff --git a/Matrices/Structures/CellsCollections/VectorSelector.cs b/Matrices/Structures/CellsCollections/VectorSelector.cs
new file mode 100644
index 0000000..421cdf6
--- /dev/null
+++ b/Matrices/Structures/CellsCollections/VectorSelector.cs
@@ -0,0 +1,17 @@
+namespace MathExtended.Matrices.Structures.CellsCollections
+{
+ ///
+ /// Селектор выборо векторов матрицы(вектор-строка или вектро-столбец)
+ ///
+ public enum VectorSelector
+ {
+ ///
+ /// Строка
+ ///
+ Rows = 1,
+ ///
+ /// Столбец
+ ///
+ Columns = 2
+ }
+}
diff --git a/Matrices/Structures/Columns/Column.cs b/Matrices/Structures/Columns/Column.cs
new file mode 100644
index 0000000..614c90d
--- /dev/null
+++ b/Matrices/Structures/Columns/Column.cs
@@ -0,0 +1,189 @@
+using MathExtended.Exceptions;
+using MathExtended.Matrices.Structures.CellsCollection;
+using MathExtended.Matrices.Structures.Rows;
+using MiscUtil;
+using System;
+
+namespace MathExtended.Matrices.Structures.Columns
+{
+ ///
+ /// Описывает столбец матрицы
+ ///
+ /// Тип содержимого строки
+ public class Column : BaseCellsCollection where T : IComparable, IFormattable, IConvertible, IComparable, IEquatable
+ {
+ private BaseCellsCollection ColumnCells;
+ ///
+ /// Создает столбец с указанными размерами
+ ///
+ ///
+ public Column(int height) : base(height) { }
+ ///
+ /// Создает столбец на основе массива
+ ///
+ ///
+ public Column(T[] array) : base(array) { }
+
+ ///
+ /// Не явным образом приводит масив к столбцу
+ ///
+ /// Приводимый массив
+ public static implicit operator Column(T[] array)
+ {
+ return new Column(array);
+ }
+
+ ///
+ /// Умножает число на столбец
+ ///
+ /// Множитель
+ /// Столбец
+ /// Умноженый столбец
+ public static Column operator *(T multiplier, Column column)
+ {
+ Column multipliedColumn = new Column(column.Size);
+
+ int i = 0;
+
+ column.ForEach((cell) => multipliedColumn[i++] = Operator.Multiply(cell, multiplier));
+
+ return multipliedColumn;
+ }
+
+ ///
+ /// Умножает число на столбец
+ ///
+ /// Множитель
+ /// Столбец
+ /// Умноженный столбец
+ public static Column operator *(Column column, T multiplier)
+ {
+ Column multipliedColumn = new Column(column.Size);
+
+ int i = 0;
+
+ column.ForEach((cell) => multipliedColumn[i++] = Operator.Multiply(cell, multiplier));
+
+ return multipliedColumn;
+ }
+
+ ///
+ /// Складывает столбцы
+ ///
+ /// Первый столбец
+ /// Второй столбец
+ /// Сумма двух столбцов
+ public static Column operator +(Column columnA, Column columnB)
+ {
+ if (columnA.Size == columnB.Size)
+ {
+ Column summedColumn = new Column(columnA.Size);
+
+ int i = 0;
+
+ summedColumn.ForEach((cell) => summedColumn[i++] = Operator.Add(columnA[i++], columnB[i++]));
+
+ return summedColumn;
+ }
+ else
+ {
+ throw new ColumnsOfDifferentSizesException();
+ }
+ }
+
+ ///
+ /// Вычетает столбцы
+ ///
+ /// Первый столбец
+ /// Второй столбец
+ /// Разность двух столбцов
+ public static Column operator -(Column columnA, Column columnB)
+ {
+ if (columnA.Size == columnB.Size)
+ {
+ Column summedColumn = new Column(columnA.Size);
+
+ int i = 0;
+
+ summedColumn.ForEach((cell) => summedColumn[i++] = Operator.Subtract(columnA[i++], columnB[i++]));
+
+ return summedColumn;
+ }
+ else
+ {
+ throw new ColumnsOfDifferentSizesException();
+ }
+ }
+
+ ///
+ /// Умножает столбец на строку
+ ///
+ /// Столбец
+ /// Строка
+ /// результат умножения
+ public static Matrix operator *(Column column, Row