Skip to content

Commit

Permalink
Merge pull request #45 from SergeyKuz1001/Task02
Browse files Browse the repository at this point in the history
Task02_Kuzivanov
  • Loading branch information
EgorkaKulikov authored Dec 10, 2019
2 parents 92daa0e + c534543 commit e68f63e
Show file tree
Hide file tree
Showing 7 changed files with 478 additions and 0 deletions.
64 changes: 64 additions & 0 deletions Task02/GeneralResources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.IO;

namespace Task02
{
public class Graph
{
public const int INF = 1000000000;
public int[,] graphMatrix;
public (int, int, int)[] graphListEdges;
public int graphAmountVertexes;
static int NumberOfConventionalUnitsInTotal = 1000000;

public Graph(int amountVertexes, int approximateAmountEdges, int minWeight, int maxWeight)
{
graphAmountVertexes = amountVertexes;
graphMatrix = new int[amountVertexes, amountVertexes];
Random random = new Random();
int partAmountEdgesFromMax = (int)((long)approximateAmountEdges * NumberOfConventionalUnitsInTotal /
(amountVertexes * (amountVertexes - 1) / 2));
int exectAmountEdges = 0;
for (int i = 0; i < amountVertexes; i++)
{
for (int j = i + 1; j < amountVertexes; j++)
{
if (random.Next(NumberOfConventionalUnitsInTotal) < partAmountEdgesFromMax)
{
int weight = random.Next(minWeight, maxWeight);
graphMatrix[i, j] = graphMatrix[j, i] = weight;
exectAmountEdges++;
}
else
{
graphMatrix[i, j] = graphMatrix[j, i] = INF;
}
}
}

graphListEdges = new (int, int, int)[exectAmountEdges];
int k = 0;
for (int i = 0; i < amountVertexes; i++)
{
for (int j = i + 1; j < amountVertexes; j++)
{
if (graphMatrix[i, j] != INF)
{
graphListEdges[k] = (graphMatrix[i, j], i, j);
k++;
}
}
}

StreamWriter foutMatrix = new StreamWriter("matrix.txt");
foutMatrix.Write($"{amountVertexes} {exectAmountEdges}\n");
for (k = 0; k < exectAmountEdges; k++)
{
foutMatrix.Write($"{graphListEdges[k].Item2 + 1} " +
$"{graphListEdges[k].Item3 + 1} " +
$"{graphListEdges[k].Item1}\n");
}
foutMatrix.Close();
}
}
}
54 changes: 54 additions & 0 deletions Task02/ParallelAlgoFloyd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;

namespace Task02
{
public class ParallelAlgoFloyd
{
private static int[,] dist;

static void parallelProc(int n, int k, int i)
{
for (int j = 0; j < n; j++)
{
if (j != k)
{
if (dist[i, j] > dist[i, k] + dist[k, j])
dist[i, j] = dist[i, k] + dist[k, j];
}
}
}

public static int[,] Execute(Graph graph)
{
int n = graph.graphAmountVertexes;
dist = new int[n, n];
Task[] tasks = new Task[n - 1];
Array.Copy(graph.graphMatrix, dist, n * n);

for (int k = 0; k < n; k++)
{
for (int i = 0; i < n; i++)
{
if (i != k)
{
int newK = k;
int newI = i;
// передаём newK и newI для того, чтобы избежать замыкания
tasks[i < k ? i : i - 1] = Task.Run(() => parallelProc(n, newK, newI));
// так как i из 0..(n-1), но одно из значений i не используется (блокируется
// условием i != k), то для единообразия обработки Task tasks.Length == n - 1,
// и выражение (i < k ? i : i - 1) задаёт биекцию из [0; k-1] U [k+1; n-1] в
// [0; n-2]
}
}
// ждём выполнения всех задач для того, чтобы случайно не получилось так, что
// задача с большим k не обогнала задачу с меньшим k (и чтобы нам всегда хватило
// ровно n - 1 задачи)
Task.WaitAll(tasks);
}

return dist;
}
}
}
86 changes: 86 additions & 0 deletions Task02/ParallelAlgoKruskal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Threading;

namespace Task02
{
public class ParallelAlgoKruskal
{
static Random rand = new Random();
static int[] dsu;
static int parallelDepth = 3; // глубина рекурсии, до которой происходит распараллеливание сортировки рёбер

static int getDsu(int x)
{
return dsu[x] == -1 ? x : dsu[x] = getDsu(dsu[x]);
}

static bool unionDsu(int x, int y)
{
x = getDsu(x);
y = getDsu(y);
if (x == y)
return false;
if (rand.Next(0, 1) == 1) // псевдорандом
dsu[y] = x;
else
dsu[x] = y;
return true;
}

static void parallelSort<T>(T[] edges, T[] buffer, int LIndex, int RIndex, int parallelDepth) where T : IComparable<T>
{
// parallelSort до глубины parallelDepth реализуется как параллельная MergeSort, а глубже - встроенную сортировку
if (parallelDepth <= 0)
{
Array.Sort(edges, LIndex, RIndex - LIndex);
return;
}
if (RIndex - LIndex <= 1)
return;
int MIndex = (LIndex + RIndex) / 2;

// чтобы поток просто так не стоял, он берёт на себя сортировку половины массива, а другую отдаёт новому потоку
Thread helperThread = new Thread(() => parallelSort(edges, buffer, LIndex, MIndex, parallelDepth - 1));
helperThread.Start();
parallelSort(edges, buffer, MIndex, RIndex, parallelDepth - 1);
helperThread.Join();

// объединение двух отсортированных массивов через buffer
int i = LIndex, j = MIndex;
for (int k = LIndex; k < RIndex; k++)
{
if (i == MIndex || (j != RIndex && edges[i].CompareTo(edges[j]) >= 0))
{
buffer[k] = edges[j];
j++;
}
else
{
buffer[k] = edges[i];
i++;
}
}
for (int k = LIndex; k < RIndex; k++)
edges[k] = buffer[k];
}

public static int Execute(Graph graph)
{
int ans = 0;
(int, int, int)[] edges = graph.graphListEdges;
parallelSort(edges, new (int, int, int)[edges.Length], 0, edges.Length, parallelDepth);

dsu = new int[graph.graphAmountVertexes];
Array.Fill(dsu, -1);

for (int i = 0; i < edges.Length; i++)
{
if (unionDsu(edges[i].Item2, edges[i].Item3))
{
ans += edges[i].Item1;
}
}
return ans;
}
}
}
91 changes: 91 additions & 0 deletions Task02/ParallelAlgoPrim.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Threading;
using System.Collections.Generic;

namespace Task02
{
public class ParallelAlgoPrim
{
static int minDistVertex; // вершина, не лежащая в дереве, расстояние до которой от дерева минимально
static int newMinDistVertex;
static int amountThreads = 6;
static int runningThreads; // количество выполняющихся потоков
static int chunkSize;
static Mutex mutRunningThreads = new Mutex(); // блокировка при изменении runningThreads
static Mutex mutNewV = new Mutex(); // блокировка при чтении и изменении newV
static HashSet<int> tree; // вершины, лежащие в остовном дереве
static int[] minDistToTree;

static void FindNewV(Graph graph, int LIndex, int RIndex)
{
// нахождение очередной вершины с минимальным расстоянием до дерева
int localMinDistVertex = -1; // локальный ответ

for (int to = LIndex; to < RIndex; to++)
{
if (!tree.Contains(to))
{
// обновление минимального расстояния после добавления v в дерево
if (minDistToTree[to] > graph.graphMatrix[minDistVertex, to])
{
minDistToTree[to] = graph.graphMatrix[minDistVertex, to];
}

// обновление локального ответа
if (localMinDistVertex == -1 || minDistToTree[localMinDistVertex] > minDistToTree[to])
localMinDistVertex = to;
}
}

if (localMinDistVertex != -1)
{
mutNewV.WaitOne();
// обновление глобального ответа
if (newMinDistVertex == -1 || minDistToTree[newMinDistVertex] > minDistToTree[localMinDistVertex])
newMinDistVertex = localMinDistVertex;
mutNewV.ReleaseMutex();
}

mutRunningThreads.WaitOne();
runningThreads--;
mutRunningThreads.ReleaseMutex();
}

public static int Execute(Graph graph)
{
int ans = 0;
tree = new HashSet<int>();
minDistToTree = new int[graph.graphAmountVertexes];
Array.Fill(minDistToTree, Graph.INF);
chunkSize = graph.graphAmountVertexes / amountThreads;

// начинаем с вершины 0
minDistToTree[0] = 0;
minDistVertex = 0;

while (minDistVertex != -1)
{
ans += minDistToTree[minDistVertex];
tree.Add(minDistVertex);

newMinDistVertex = -1;

runningThreads = amountThreads;
for (int i = 0; i < amountThreads - 1; i++)
{
int LIndex = chunkSize * i;
int RIndex = chunkSize * (i + 1);
ThreadPool.QueueUserWorkItem(_ => FindNewV(graph, LIndex, RIndex));
}
// загрзим главный поток чтобы он просто так не ждал
FindNewV(graph, chunkSize * (amountThreads - 1), graph.graphAmountVertexes);

while (runningThreads > 0) {}

minDistVertex = newMinDistVertex;
}

return ans;
}
}
}
Loading

0 comments on commit e68f63e

Please sign in to comment.