我有这个uni项目,在这里我需要计算具有m个线程的给定NxN矩阵的行列式。经过20个小时没有做任何事情,我最终设法创造出一种与在网上流通的行列式略有不同的方法。
基本上,我有一个Class Matrica,其中保存[,]矩阵,其子矩阵以及计算行列式所需的adj值和索引。
我认为我需要在visit方法的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;
}
}
我尝试将任务和线程与Lambda初始化一起使用,但我以某种方式使索引超出范围异常。如果我<5,则在循环中会以某种方式在我5岁时出现异常,而我真的不知道为什么。
这就是我想出的。具有0个线程的10x10运行时间约为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);
}
答案 0 :(得分:0)
使用 Sarrus规则(非递归方法)示例使用Javascript,但可以轻松地用C#编写 https://github.com/apanasara/Faster_nxn_Determinant
nxn行列式计算仅需两个循环...因此,可以在单线程上完成