У меня есть этот универсальный проект, в котором мне нужно вычислить определитель заданной матрицы NxN с числом потоков m.После 20 часов, когда я ничего не делал, мне в итоге удалось создать немного иной способ вычисления определителя, чем тот, который циркулирует в сети.
В основном у меня есть Class Matrica, которая содержит матрицу [,],его подматрицы, а также значения приставки и индекс, необходимые для вычисления определителя.
Я думаю, что мне нужно использовать потоки в операторе else в методе посещения.
class Program
{
static double[,] matrix3x3 = new double[3, 3] {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
}; // det is 0
static double[,] matrix4x4 = new double[4, 4] {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 }
}; // det is 0
static double[,] mat = new double[,]
{
{1, 0, 2, -1, 4},
{3, 0, 0, 5, 3},
{2, 1, 4, -3, 2},
{1, 0, 5, 0, 1},
{3, 2, 1, 2, 2}
}; // det is 300
public class Visitor
{
public double Visit(Matrica matrix)
{
if (matrix.getSize() == 2)
{
return ((matrix.matrix[0, 0] * matrix.matrix[1, 1]) - (matrix.matrix[1, 0] * matrix.matrix[0, 1]));
}
else
{
List<double> results = new List<double>();
for (int i = 0; i < matrix.getSize(); i++)
{
// Maybe add threads here
results.Add(matrix.subMatrixes[i].adj.Value * SignOfElement(0, matrix.subMatrixes[i].adjIndex.Value) * Visit(matrix.subMatrixes[i]));
}
return results.Sum();
}
}
}
public class Matrica
{
public double? adj;
public int? adjIndex;
public double[,] matrix;
public List<Matrica> subMatrixes = new List<Matrica>();
public int getSize()
{
return int.Parse(System.Math.Sqrt(matrix.Length).ToString());
}
public Matrica(double[,] _input, double? _adj = null, int? _adjIndex = null)
{
this.matrix = _input;
this.adj = _adj;
this.adjIndex = _adjIndex;
// maybe add threading here as well
CreateSubMatrixes();
}
public void CreateSubMatrixes()
{
int size = this.getSize();
if (size > 2)
{
for (int i = 0; i < size; i++)
{
var smallerMatrix= CreateMatrix(matrix, i);
this.subMatrixes.Add(smallerMatrix);
}
}
}
};
public static Matrica CreateMatrix(double[,] matrix, int i)
{
var smaller = CreateSmallerMatrix(matrix, 0, i);
var adj = matrix[0, i];
int adjIndex = i;
Matrica newMatrix = new Matrica(smaller, adj, adjIndex);
return newMatrix;
}
static void Main(string[] args)
{
Visitor v = new Visitor();
double res = v.Visit(mat);
Console.WriteLine(res);
}
static int SignOfElement(int i, int j)
{
if ((i + j) % 2 == 0)
{
return 1;
}
else
{
return -1;
}
}
//this method determines the sub matrix corresponding to a given element
static double[,] CreateSmallerMatrix(double[,] input, int i, int j)
{
int order = int.Parse(System.Math.Sqrt(input.Length).ToString());
double[,] output = new double[order - 1, order - 1];
int x = 0, y = 0;
for (int m = 0; m < order; m++, x++)
{
if (m != i)
{
y = 0;
for (int n = 0; n < order; n++)
{
if (n != j)
{
output[x, y] = input[m, n];
y++;
}
}
}
else
{
x--;
}
}
return output;
}
}
Я пробовалиспользуя Task и Threads с лямбда-инициализацией, но я каким-то образом получаю индекс вне диапазона исключений.Каким-то образом в циклах, если я <5, я получаю исключение, когда мне 5, и я действительно понятия не имею, почему. </p>
Это то, что я придумал.10x10 с 0 потоками работает в течение ~ 3,5 с, 12 потоков - в ~ 1,5 с.
В конце концов я получаю исключение IndexOutOfBounds, но я не знаю, как этого избежать.
static double Determinant(double[,] input, int freeThreads = 0)
{
int order = int.Parse(System.Math.Sqrt(input.Length).ToString());
if (order > 2)
{
List<double> results = new List<double>();
List<Thread> threads = new List<Thread>();
for (int j = 0; j < order; j++)
{
double[,] Temp = CreateSmallerMatrix(input, 0, j);
if (freeThreads > 0)
{
int remainingFree = 0;
if (freeThreads >= order)
{
remainingFree = freeThreads - order;
}
Thread t = new Thread(() => Worker(ref results, input[0, j], SignOfElement(0, j), Determinant(Temp, remainingFree)));
t.Start();
threads.Add(t);
freeThreads--;
} else
{
Worker(ref results, input[0, j], SignOfElement(0, j), Determinant(Temp, 0));
}
}
foreach (var item in threads)
{
item.Join();
}
return results.Sum();
}
else if (order == 2)
{
return ((input[0, 0] * input[1, 1]) - (input[1, 0] * input[0, 1]));
}
else
{
return (input[0, 0]);
}
public static void Worker(ref List<double> result, double adj, int sign, double sub)
{
result.Add(adj * sign * sub);
}