用多线程计算NxN矩阵行列式

时间:2019-06-13 23:39:45

标签: c# multithreading matrix

我有这个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);
    }

1 个答案:

答案 0 :(得分:0)

以下链接上的

使用 Sarrus规则(非递归方法)示例使用Javascript,但可以轻松地用C#编写 https://github.com/apanasara/Faster_nxn_Determinant

nxn行列式计算仅需两个循环...因此,可以在单线程上完成