Рассчитать определитель матрицы NxN с многопоточностью - PullRequest
1 голос
/ 14 июня 2019

У меня есть этот универсальный проект, в котором мне нужно вычислить определитель заданной матрицы 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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...