package edu.kit.pse.ws2013.routekit.precalculation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import edu.kit.pse.ws2013.routekit.models.ArcFlags;
import edu.kit.pse.ws2013.routekit.models.ProfileMapCombination;
import edu.kit.pse.ws2013.routekit.models.ProgressReporter;
/**
* A working {@link ArcFlagsCalculator} using multiple threads.
*
* @author Fabian Hafner
* @version 1.0
*
*/
public class ArcFlagsCalculatorParallel extends ArcFlagsCalculatorImpl {
private int currentlyCalculatedPartition;
private ProgressReporter reporter;
private List<Set<Integer>> partitions;
private int numberOfThreads;
private class Worker extends Thread {
private final int startPartition;
public Worker(final int startPartition) {
this.startPartition = startPartition;
}
@Override
public void run() {
calculateFlagsOfPartitions(startPartition);
}
}
@Override
public void calculateArcFlags(final ProfileMapCombination combination,
final ProgressReporter reporter) {
final long t1 = System.currentTimeMillis();
graph = combination.getStreetMap().getGraph();
edgeBasedGraph = combination.getStreetMap().getEdgeBasedGraph();
weights = combination.getWeights();
flagsArray = new int[edgeBasedGraph.getNumberOfTurns()];
this.reporter = reporter;
partitions = new ArrayList<Set<Integer>>(nPartitions);
reporter.setSubTasks(new float[] { .1f, .9f });
reporter.pushTask("Bereite Partitionen vor");
for (int i = 0; i < nPartitions; i++) {
partitions.add(new HashSet<Integer>());
}
for (int i = 0; i < graph.getNumberOfEdges(); i++) {
partitions.get(edgeBasedGraph.getPartition(i)).add(i);
}
reporter.nextTask("Baue Kürzeste-Pfade-Bäume zu den Schnittkanten der Partitionen auf");
currentlyCalculatedPartition = 1;
numberOfThreads = Math.max(
Runtime.getRuntime().availableProcessors() / 2, 1);
final Worker[] workers = new Worker[numberOfThreads];
for (int i = 0; i < workers.length; i++) {
workers[i] = new Worker(i);
workers[i].start();
}
try {
for (int i = 0; i < workers.length; i++) {
workers[i].join();
}
} catch (final InterruptedException e) {
e.printStackTrace();
}
reporter.popTask();
final long t2 = System.currentTimeMillis();
final int time = (int) (t2 - t1);
combination.setArcFlags(new ArcFlags(flagsArray), time);
}
private void calculateFlagsOfPartitions(final int startPartition) {
for (int currentPartition = startPartition; currentPartition < partitions
.size(); currentPartition += numberOfThreads) {
final int[] flagsArray = new int[this.flagsArray.length];
final Set<Integer> edgesWithTurnsToOtherPartitions = new HashSet<Integer>();
for (final Integer edge : partitions.get(currentPartition)) {
final Set<Integer> incomingTurns = edgeBasedGraph
.getIncomingTurns(edge);
for (final Integer turn : incomingTurns) {
final int startEdgePartition = edgeBasedGraph
.getPartition(edgeBasedGraph.getStartEdge(turn));
if (startEdgePartition == currentPartition) {
if (weights.getWeight(turn) != Integer.MAX_VALUE) {
setFlag(turn, currentPartition, flagsArray);
}
} else {
edgesWithTurnsToOtherPartitions.add(edge);
}
}
}
for (final Integer edge : edgesWithTurnsToOtherPartitions) {
buildReverseShortestPathsTreeAndSetArcFlags(edge, flagsArray);
}
synchronized (this.flagsArray) {
// write back flags
for (int i = 0; i < flagsArray.length; i++) {
this.flagsArray[i] |= flagsArray[i];
}
}
synchronized (reporter) {
reporter.setProgress(currentlyCalculatedPartition
/ (float) nPartitions);
currentlyCalculatedPartition++;
}
}
}
}