/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: PlacementForceDirectedTeam5.java
* Written by Team 5: Andreas Wagner, Thomas Hauck, Philippe Bartscherer
*
* This code has been developed at the Karlsruhe Institute of Technology (KIT), Germany,
* as part of the course "Multicore Programming in Practice: Tools, Models, and Languages".
* Contact instructor: Dr. Victor Pankratius (pankratius@ipd.uka.de)
*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.placement.forceDirected1;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;
import java.util.concurrent.CyclicBarrier;
import com.sun.electric.tool.placement.PlacementFrame;
import com.sun.electric.tool.placement.forceDirected1.metric.BBMetric;
import com.sun.electric.tool.placement.forceDirected1.metrics.PAMetric;
import com.sun.electric.util.math.GenMath.MutableInteger;
import com.sun.electric.util.math.Orientation;
public class PlacementForceDirectedTeam5 extends PlacementFrame {
// ------ Parameters from the standalone Placementframe -------------
// maximum runtime of the placement algorithm in seconds
public PlacementParameter maxRuntimeParam = new PlacementParameter("runtime", "Runtime (seconds):", 60);
// public int maxRuntime = 60;
// number of threads
public PlacementParameter maxThreadsParam = new PlacementParameter("threads", "Number of threads:", 4);
// public int numThreads = 4;
// if false: NO system.out.println statements
public boolean printDebugInformation = true;
// parameters
Heuristic p; // all global parameter
double overlapWeightingFactor;
// algorithm variables
private List<PlacementNode> nodesToPlace;
List<PlacementNetwork> allNetworks;
private Map<PlacementNode, Map<PlacementNode, MutableInteger>> connectivityMap;
Point2D.Double centerOfMass;
private double[] forceX;
private double[] forceY;
double cellCount[][];
private double mirrorGain;
public BBMetric bb;
public BBMetric bbPartial;
// information for the benchmark framework
String teamName = "team 5";
String studentName1 = "Thomas Hauck";
String studentName2 = "Andreas Wagner";
String algorithmType = "force directed";
/**
* Method to return the name of this placement algorithm.
*
* @return the name of this placement algorithm.
*/
public String getAlgorithmName() {
return "Force-Directed-1";
}
// public void setBenchmarkValues(int runtime, int threads, boolean debug) {
// maxRuntime = runtime;
// numThreads = threads;
// printDebugInformation = debug;
// }
// --- Force-Directed placement -------------------------------------------
private class Heuristic {
// --- parameter ---
public int max_iterations = 2000; // e.g. 1000
public int max_resolve = 5000; // e.g. 1000
public int max_rows = 15; // e.g. 15
public double donut_inner = 2500; // e.g. 2500
public double spread_length = 3750; // e.g. 3750
public double spread_force = 400; // e.g. 400
public double spread_slowdown = 20; // e.g. 100
// --- statistics ---
public double W; // minimum node width
public double H; // minimum node height
public double totalArea; // calculated in constructor
public double areaPerCell;
// --- public ---
public Heuristic(List<PlacementNode> nodesToPlace) {
calculateStatistics(nodesToPlace);
heuristic1(nodesToPlace);
}
/**
* my parameter for placement results
*/
private void heuristic1(List<PlacementNode> nodesToPlace) {
int nodes = nodesToPlace.size();
// better dynamic heuristic
this.max_rows = (int) (16 + Math.sqrt(nodes / 5.3));
this.donut_inner = Math.sqrt(totalArea);
this.spread_length = 1.5 * donut_inner;
this.spread_slowdown = 5;
if (totalArea < 200)
spread_force = 40;
if (nodesToPlace.size() > 500)
spread_force = 2500;
if (nodesToPlace.size() > 2000)
spread_force = 8000;
if (printDebugInformation) {
System.out.println("Heuristic3: max_rows=" + max_rows);
System.out.println("total Area: " + totalArea);
}
}
// --- statistics ---
private void calculateStatistics(List<PlacementNode> nodesToPlace) {
getMinDimensions(nodesToPlace);
this.totalArea = getTotalArea(nodesToPlace);
this.areaPerCell = totalArea / (max_rows * max_rows);
}
private double getTotalArea(List<PlacementNode> nodesToPlace) {
double area = 0;
for (int i = 0; i < nodesToPlace.size(); i++) {
area += nodesToPlace.get(i).getWidth() * nodesToPlace.get(i).getHeight();
}
return area;
}
/**
* Get dimensions of the smallest node.
*/
private void getMinDimensions(List<PlacementNode> nodesToPlace) {
// inputs: nodesToPlace
// outputs: W, H
this.W = Double.MAX_VALUE;
this.H = Double.MAX_VALUE;
for (PlacementNode node : nodesToPlace) {
if (node.getWidth() > 0)
W = Math.min(node.getWidth(), W);
if (node.getHeight() > 0)
H = Math.min(node.getHeight(), H);
}
}
}
/*
* (non-Javadoc)
*
* @see
* com.sun.electric.tool.placement.PlacementFrame#setParamterValues(int,
* int)
*/
@Override
public void setParamterValues(int threads, int runtime) {
// TODO Auto-generated method stub
super.setParamterValues(threads, runtime);
}
/**
* Method to do Force-Directed Placement.
*
* @param nodesToPlace
* a list of all nodes that are to be placed.
* @param allNetworks
* a list of all networks that connect the nodes.
* @param cellName
* the name of the cell being placed.
*/
public void runPlacement(List<PlacementNode> nodesToPlace, List<PlacementNetwork> allNetworks,
String cellName) {
this.setParamterValues(this.maxThreadsParam.getIntValue(), this.maxRuntimeParam.getIntValue());
initTimeout(0);
bb = new BBMetric();
bbPartial = new BBMetric();
// initialize algorithm
dbg = new Debug(); // debug object
if (printDebugInformation) {
bb.setBenchmarkValues(nodesToPlace, allNetworks);
dbg.tick(); // total time
dbg.tick(); // initialization time
}
// parameter
this.nodesToPlace = nodesToPlace;
this.allNetworks = allNetworks;
this.p = new Heuristic(nodesToPlace); // calculate all default
// parameters
overlapWeightingFactor = 0;
// allocate variables
centerOfMass = new Point2D.Double();
forceX = new double[nodesToPlace.size()];
forceY = new double[nodesToPlace.size()];
cellCount = new double[p.max_rows][p.max_rows];
// build connectivity map
if (printDebugInformation) {
dbg.println("=== FORCE-DIRECTED =====================");
}
buildConnectivityMap(allNetworks);
randomPlaceDonut(p.donut_inner, p.donut_inner / 4); // e.g. 2500, 500
if (printDebugInformation) {
dbg.tack("Initialization");
}
swapNodes();
// force directed placement
if (printDebugInformation) {
dbg.println("Threads", numOfThreads);
dbg.println("Nodes", nodesToPlace.size());
dbg.tick();
}
// phase1 : calculate forces and move nodes
// --- parallel ---
initTimeout(1);
startThreads(); // step1 & step2 (parallel)
waitThreads();
if (printDebugInformation) {
dbg.tack("Phase1", true);
}
// phase2 : resolve overlapping nodes
overlapWeightingFactor = 1;
PAMetric chipArea = new PAMetric(nodesToPlace, allNetworks);
boolean overlap = true;
int i = 0;
double whRatio = 1;
calculateCenterOfMass(); // step3
initTimeout(2);
for (i = 0; overlap && i < p.max_resolve && checkTimeout(); i++) { // step4
chipArea.compute();
whRatio = chipArea.getWidth() / chipArea.getHeight();
if (nodesToPlace.size() > 3000
|| ((nodesToPlace.size() > 1000 && nodesToPlace.size() < 3000 && runtime < 120))) {
overlap = resolveOverlapsFast(overlapWeightingFactor, whRatio);
} else {
overlap = resolveOverlaps(overlapWeightingFactor, whRatio);
}
}
if (printDebugInformation) {
dbg.println("Number of resolve Steps: " + i);
dbg.tack("Phase2");
dbg.println("=== after resolve Overlap ==============================");
dbg.println(bb.toString()); // metric
}
// rotate nodes
initTimeout(3);
iterativeFindOrientations(nodesToPlace);
if (printDebugInformation) {
dbg.println("=== after rotation/mirroring ======================");
dbg.println(bb.toString()); // metric
}
// fill empty bins
initTimeout(4);
fillEmptyBins();
if (printDebugInformation) {
dbg.println("=== after fillEmptyBins ======================");
dbg.println(bb.toString()); // metric
}
// shake nodes
initTimeout(5);
shakeNodes();
if (printDebugInformation) {
dbg.println("=== after shakeNodes ======================");
dbg.println(bb.toString()); // metric
dbg.println("=== FINAL placement ======================");
dbg.tack("Total"); // total time
dbg.println(bb.toString()); // metric
dbg.flush();
}
}
// --- algorithm : phase1 --------------------------------------------------
/**
* Step1: method to calculate attracting and repulsing forces
*
*/
private void calculateForces(int firstIndex, int lastIndex) {
PlacementNode node1; // !faster
PlacementNode node2; // !faster
// attracting forces
// inputs: nodesToPlace, connectivityMap
// outputs: forceX[], forceY[]
for (int i = firstIndex; i <= lastIndex && checkTimeout(); i++) {
// clear output
forceX[i] = 0;
forceY[i] = 0;
// loop cells
node1 = nodesToPlace.get(i);
Iterator<Entry<PlacementNode, MutableInteger>> destMapIterator;
Map<PlacementNode, MutableInteger> destMap = connectivityMap.get(node1);
if (destMap != null) {
destMapIterator = destMap.entrySet().iterator();
while (destMapIterator.hasNext()) {
Entry<PlacementNode, MutableInteger> srcEntry = destMapIterator.next();
node2 = srcEntry.getKey();
forceX[i] += (node2.getPlacementX() - node1.getPlacementX())
* destMap.get(node2).intValue();
forceY[i] += (node2.getPlacementY() - node1.getPlacementY())
* destMap.get(node2).intValue();
}
}
}
// repulsing forces for overlaps
// inputs: nodesToPlace, forceX[], forceY[]
// outputs: forceX[], forceY[]
for (int i = firstIndex; i <= lastIndex && checkTimeout(); i++) {
node1 = nodesToPlace.get(i);
int x = getCol(node1);
int y = getRow(node1);
if (cellCount[x][y] > p.areaPerCell) {
try {
if (cellCount[x - 1][y] < p.areaPerCell) {
forceX[i] -= Math.min(5 * p.spread_force, (cellCount[x][y] / p.areaPerCell)
* (-p.spread_force * cellCount[x - 1][y] / p.areaPerCell + p.spread_force));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (cellCount[x + 1][y] < p.areaPerCell) {
forceX[i] += Math.min(5 * p.spread_force, (cellCount[x][y] / p.areaPerCell)
* (-p.spread_force * cellCount[x + 1][y] / p.areaPerCell + p.spread_force));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (cellCount[x][y - 1] < p.areaPerCell) {
forceY[i] -= Math.min(5 * p.spread_force, (cellCount[x][y] / p.areaPerCell)
* (-p.spread_force * cellCount[x][y - 1] / p.areaPerCell + p.spread_force));
}
} catch (IndexOutOfBoundsException e) {
}
try {
if (cellCount[x][y + 1] < p.areaPerCell) {
forceY[i] += Math.min(5 * p.spread_force, (cellCount[x][y] / p.areaPerCell)
* (-p.spread_force * cellCount[x][y + 1] / p.areaPerCell + p.spread_force));
}
} catch (IndexOutOfBoundsException e) {
}
}
}
}
private void count() {
for (int i = 0; i < p.max_rows; i++) {
for (int j = 0; j < p.max_rows; j++) {
cellCount[i][j] = 0;
}
}
for (PlacementNode node : nodesToPlace) {
cellCount[getCol(node)][getRow(node)] += Math.min(p.areaPerCell, node.getHeight()
* node.getWidth());
}
}
int getCol(PlacementNode node) {
int x = (int) (node.getPlacementX() * p.max_rows / p.spread_length);
if (x < 0)
x = 0;
else if (x >= p.max_rows)
x = p.max_rows - 1;
return x;
}
int getRow(PlacementNode node) {
int y = (int) (node.getPlacementY() * p.max_rows / p.spread_length);
if (y < 0)
y = 0;
else if (y >= p.max_rows)
y = p.max_rows - 1;
return y;
}
/**
* Step2 : move all nodes to new position
*
* @param weightingFactor
*/
private void moveCells(double weightingFactor) {
// loop all nodes
PlacementNode node;
int size = nodesToPlace.size();
for (int i = 0; i < size; i++) {
node = nodesToPlace.get(i);
node.setPlacement(node.getPlacementX() + forceX[i] * weightingFactor, node.getPlacementY()
+ forceY[i] * weightingFactor);
}
}
// --- algorithm : phase2 ---------------------------------------------
/**
* Step4 : calculate mass center of all nodes
*
*/
private void calculateCenterOfMass() {
// inputs: nodesToPlace
// outputs: centerOfMass
double x = 0;
double y = 0;
double mass = 0;
double totalMass = 0;
PlacementNode node;
// loop cells
for (int i = 0; i < nodesToPlace.size(); i++) {
node = nodesToPlace.get(i);
mass = node.getHeight() * node.getWidth();
x += node.getPlacementX() * mass;
y += node.getPlacementY() * mass;
totalMass += mass;
}
centerOfMass.setLocation(x / totalMass, y / totalMass);
}
/**
* Step5 : resolves overlapping cells
*
* @param overlapWeightingFactor
* @param shapeRatio
* @return
*/
boolean resolveOverlaps(double overlapWeightingFactor, double shapeRatio) {
// inputs : nodesToPlace, centerOfMass, W, H
boolean isOverlapping = false;
PlacementNode node1;
PlacementNode node2;
Point2D.Double overlap = new Point2D.Double();
double distNode1;
double distNode2;
double sigma1;
double sigma2;
final double lowerBound = 0.6;
final double upperBound = 1.8;
int size = nodesToPlace.size(); // number of nodes to place
for (int i = 0; i < size && checkTimeout(); i++) {
node1 = nodesToPlace.get(i);
for (int j = i + 1; j < size && checkTimeout(); j++) {
node2 = nodesToPlace.get(j);
if (getOverlap(node1, node2, overlap) != 0) {
isOverlapping = true;
distNode1 = Math.abs(centerOfMass.x - node1.getPlacementX())
+ Math.abs(centerOfMass.y - node1.getPlacementY());
distNode2 = Math.abs(centerOfMass.x - node2.getPlacementX())
+ Math.abs(centerOfMass.y - node2.getPlacementY());
sigma1 = 0;
sigma2 = 0;
if (distNode1 > distNode2) { // move node1
if (overlap.y / overlap.x > lowerBound)
sigma1 = (node1.getPlacementX() - centerOfMass.x) / distNode1;
if (overlap.y / overlap.x < upperBound)
sigma2 = (node1.getPlacementY() - centerOfMass.y) / distNode1;
if (shapeRatio > 1) // ! new: consider square shape
sigma1 *= 0.1; //
else if (shapeRatio < 1) //
sigma2 *= 0.1; //
node1.setPlacement(node1.getPlacementX() + overlapWeightingFactor * sigma1 * p.W,
node1.getPlacementY() + sigma2 * p.H);
} else { // move node2
if (overlap.y / overlap.x > lowerBound)
sigma1 = (node2.getPlacementX() - centerOfMass.x) / distNode2;
if (overlap.y / overlap.x < upperBound)
sigma2 = (node2.getPlacementY() - centerOfMass.y) / distNode2;
if (shapeRatio > 1) // ! new: consider square shape
sigma1 *= 0.1; //
else if (shapeRatio < 1) //
sigma2 *= 0.1; //
node2.setPlacement(node2.getPlacementX() + overlapWeightingFactor * sigma1 * p.W,
node2.getPlacementY() + sigma2 * p.H);
}
}
}
}
return isOverlapping;
}
/**
* Step5 : resolves overlapping cells
*
* @param overlapWeightingFactor
* @param shapeRatio
* @return
*/
boolean resolveOverlapsFast(double overlapWeightingFactor, double shapeRatio) {
// inputs : nodesToPlace, centerOfMass, W, H
boolean isOverlapping = false;
PlacementNode node1;
PlacementNode node2;
Point2D.Double overlap = new Point2D.Double();
double distNode1;
double distNode2;
int size = nodesToPlace.size(); // number of nodes to place
for (int i = 0; i < size && checkTimeout(); i++) {
node1 = nodesToPlace.get(i);
for (int j = i + 1; j < size && checkTimeout(); j++) {
node2 = nodesToPlace.get(j);
if (getOverlap(node1, node2, overlap) != 0) {
isOverlapping = true;
distNode1 = Math.abs(centerOfMass.x - node1.getPlacementX())
+ Math.abs(centerOfMass.y - node1.getPlacementY());
distNode2 = Math.abs(centerOfMass.x - node2.getPlacementX())
+ Math.abs(centerOfMass.y - node2.getPlacementY());
if (distNode1 > distNode2) { // move node1
if (Math.random() >= 0.5) {
node1.setPlacement(node1.getPlacementX() + 1.00001 * (overlap.x)
* Math.signum(centerOfMass.x - node1.getPlacementX()), node1
.getPlacementY());
} else {
node1.setPlacement(node1.getPlacementX(), node1.getPlacementY() + 1.00001
* (overlap.y) * Math.signum(centerOfMass.y - node1.getPlacementY()));
}
} else {
if (Math.random() >= 0.5) {
node2.setPlacement(node2.getPlacementX() + 1.00001 * (overlap.x)
* Math.signum(centerOfMass.x - node2.getPlacementX()), node2
.getPlacementY());
} else {
node2.setPlacement(node2.getPlacementX(), node2.getPlacementY() + 1.00001
* (overlap.y) * Math.signum(centerOfMass.y - node2.getPlacementY()));
}
}
}
}
}
return isOverlapping;
}
// --- Algorithm : private methods ----------------------------------------
/**
* Initial placement for all nodes. Place them randomly in form of a square
* donut.
*
* @param innerSize
* @param border
*/
private void randomPlaceDonut(double innerSize, double border) {
Random rand = new Random(1); // pseudo random
double posX;
double posY;
for (PlacementNode node : nodesToPlace) {
do {
posX = rand.nextDouble() * (2 * border + innerSize);
posY = rand.nextDouble() * (2 * border + innerSize);
} while (posX > border && posX < innerSize + border && posY > border && posY < innerSize + border);
node.setPlacement(posX, posY);
}
}
/**
* Calculate the smallest step a node can move.
*
* @return smallest step
*/
private double getMobilityFactor() {
// inputs: forceX[], forceY[]
double avg = 0;
double max = 0;
double vectorLength = 0;
int size = forceX.length;
for (int i = 0; i < size; i++) {
vectorLength = Math.abs(forceX[i]) + Math.abs(forceY[i]);
avg += vectorLength;
if (vectorLength > max)
max = vectorLength;
}
avg /= forceX.length;
if (max == 0)
max = 1;
return avg / (p.spread_slowdown * max);
}
/**
* Returns absolute value of Overlap between 2 nodes. Method optimized, 2
* times faster.
*
* @param node1
* @param node2
* @param out
* @return overlapping area
*/
private double getOverlap(PlacementNode node1, PlacementNode node2, Point2D.Double out) {
double diffX = Math.abs(node1.getPlacementX() - node2.getPlacementX());
double diffY = Math.abs(node1.getPlacementY() - node2.getPlacementY());
double overlapX = Math.min(0, diffX - (node1.getWidth() + node2.getWidth()) / 2);
double overlapY = Math.min(0, diffY - (node1.getHeight() + node2.getHeight()) / 2);
out.setLocation(overlapX, overlapY);
return overlapX * overlapY;
}
/**
* Create a datastructure to efficiently find the number of connection
* between two nodes.
*
* @param allNetworks
*/
private void buildConnectivityMap(List<PlacementNetwork> allNetworks) {
connectivityMap = new HashMap<PlacementNode, Map<PlacementNode, MutableInteger>>();
for (int i = 0; i < allNetworks.size(); i++) {
List<PlacementPort> currentPortList = allNetworks.get(i).getPortsOnNet();
PlacementPort previousPlacementPort = null;
for (int j = 0; j < currentPortList.size(); j++) {
PlacementPort currentPlacementPort = currentPortList.get(j);
if (previousPlacementPort != null) {
incrementMap(previousPlacementPort.getPlacementNode(), currentPlacementPort
.getPlacementNode());
incrementMap(currentPlacementPort.getPlacementNode(), previousPlacementPort
.getPlacementNode());
}
previousPlacementPort = currentPlacementPort;
}
}
}
/**
* Method to build the connectivity map by adding a connection between two
* PlacementNodes. This method is usually called twice with the
* PlacementNodes in both orders because the mapping is not symmetric.
*
* @param plNode1
* the first PlacementNode.
* @param plNode2
* the second PlacementNode.
*/
private void incrementMap(PlacementNode plNode1, PlacementNode plNode2) {
Map<PlacementNode, MutableInteger> destMap = connectivityMap.get(plNode1);
if (destMap == null)
connectivityMap.put(plNode1, destMap = new HashMap<PlacementNode, MutableInteger>());
MutableInteger mi = destMap.get(plNode2);
if (mi == null)
destMap.put(plNode2, mi = new MutableInteger(0));
mi.increment();
}
// --- Threads : classes --------------------------------------------------
/**
* Classes to encapsulate multithreading, synchronization and single steps
* of the Force-Directed algorithm.
*
* class WorkerThread class JoinThread
*/
private Thread task[];
private WorkerThread worker[];
private CyclicBarrier barrier;
private class WorkerThread implements Runnable {
private int firstIndex; // first index of node
private int lastIndex; // last index of node
// debug
public Debug dbg = new Debug();
public WorkerThread(int firstNode, int lastNode) {
this.firstIndex = firstNode;
this.lastIndex = lastNode;
}
// algorithm
public void run() {
// phase1 : contract cells
for (int i = 0; i < p.max_iterations && checkTimeout(); i++) {
calculateForces(firstIndex, lastIndex); // step1
syncThreads(); // wait for all threads
}
barrier.reset();
}
}
private class JoinThread implements Runnable {
// algorithm
public void run() {
count();
moveCells(getMobilityFactor()); // step2
}
}
// --- Threads : private methods ------------------------------------------
/**
* Create and start all threads used in Force-Directed placement.
*
*/
private void startThreads() {
// inputs: nodesToPlace
// outputs: task[], worker[]
int numThreads = numOfThreads;
task = new Thread[numThreads];
worker = new WorkerThread[numThreads];
barrier = new CyclicBarrier(numThreads, new JoinThread());
int first = 0;
int delta = nodesToPlace.size() / numThreads;
for (int i = 0; i < numThreads; i++) {
if (i == numThreads - 1)
delta = nodesToPlace.size() - first;
worker[i] = new WorkerThread(first, first + delta - 1);
task[i] = new Thread(worker[i]);
task[i].start();
first += delta;
}
}
/**
* Synchronize all threads used in Force-Directed placement.
*
*/
private void syncThreads() {
try {
barrier.await();
} catch (Exception e) {
}
}
/**
* Wait until all threads finished their work.
*
*/
private void waitThreads() {
for (Thread t : task)
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (printDebugInformation) {
for (int i = 0; i < numOfThreads; i++) {
worker[i].dbg.flush("=== THREAD-" + i + " ===========================");
task[i] = null;
worker[i] = null;
}
barrier = null;
}
}
/**
* Timeout threads, if they work too long.
*/
private long timeoutStart;
private long timeoutEnd; // timeout for the complete algorithm, hard
// deadline
private long timeoutLevel; // timeout for current phase
private void initTimeout(int phase) {
int maxRuntime = runtime;
switch (phase) {
case 0: // swapNodes
timeoutStart = System.currentTimeMillis();
timeoutEnd = timeoutStart + (maxRuntime * 1000);
timeoutLevel = timeoutStart + (long) (maxRuntime * 1000 * 0.10); // phase1
// 10%
break;
case 1: // moveCells
timeoutLevel = timeoutStart + (long) (maxRuntime * 1000 * 0.50); // phase2
// 50%
break;
case 2: // resolveOverlap
timeoutLevel = timeoutStart + (long) (maxRuntime * 1000 * 0.95);
break;
case 3: // rotateNodes
timeoutLevel = timeoutStart + (long) (maxRuntime * 1000 * 0.55);
break;
case 4: // fillEmptyBins
timeoutLevel = timeoutStart + (long) (maxRuntime * 1000 * 0.60);
break;
case 5: // shakeNodes
timeoutLevel = timeoutEnd;
break;
}
}
/**
* Timeout threads in each phase, if they work too long.
*
* @return true = go on, false = timed out
*/
private boolean checkTimeout() {
return System.currentTimeMillis() < timeoutLevel;
}
// --- debugger ------------------------------------------------------------
// globals
private Debug dbg = null;
// methods
public void setDebugger(Debug dbg) {
this.dbg = dbg;
}
private void iterativeFindOrientations(List<PlacementNode> nodesToRotate) {
if (!checkTimeout())
return; // exit if no time is left
do { // else improve placement and rotate nodes
mirrorGain = 0;
findOrientations(nodesToRotate);
} while (mirrorGain > 0);
}
/**
* Method to find a better orientation for all of the nodes at the bottom
* point. 4 options for Mirroring are considered for each PlacementNode
* including no change
*
* @param allNodes
* a List of PlacementNodes that have location, but not ideal
* orientation.
* @return a Map assigning orientation to each of the PlacementNodes in the
* list.
*/
private void findOrientations(List<PlacementNode> nodesToRotate) {
// check timeout
if (!checkTimeout())
return;
//
double lengthNoMirror;
double lengthXMirror;
double lengthYMirror;
double lengthXYMirror;
for (int i = 0; i < nodesToRotate.size() && checkTimeout(); i++) {
PlacementNode currentNode = nodesToRotate.get(i);
List<PlacementNetwork> currentNetworks = getNetworks(currentNode);
bbPartial.setBenchmarkValues(nodesToPlace, currentNetworks);
LinkedList<PlacementNetwork> connectedNetworks = new LinkedList<PlacementNetwork>();
LinkedList<Point2D.Double> srcPoints = new LinkedList<Point2D.Double>();
for (int j = 0; j < currentNode.getPorts().size(); j++) {
connectedNetworks.add(currentNode.getPorts().get(j).getPlacementNetwork());
srcPoints.add(getAbsolutePositionOf(currentNode.getPorts().get(j)));
}
lengthNoMirror = bbPartial.compute();
int currentRotation = currentNode.getPlacementOrientation().getAngle();
boolean isXMirrored = currentNode.getPlacementOrientation().isXMirrored();
boolean isYMirrored = currentNode.getPlacementOrientation().isYMirrored();
currentNode.setOrientation(Orientation.fromJava(currentRotation, !isXMirrored, isYMirrored));
lengthXMirror = bbPartial.compute();
currentNode.setOrientation(Orientation.fromJava(currentRotation, isXMirrored, !isYMirrored));
lengthYMirror = bbPartial.compute();
currentNode.setOrientation(Orientation.fromJava(currentRotation, !isXMirrored, !isYMirrored));
lengthXYMirror = bbPartial.compute();
if ((lengthNoMirror <= lengthXMirror) && (lengthNoMirror <= lengthYMirror)
&& (lengthNoMirror <= lengthXYMirror)) {
currentNode.setOrientation(Orientation.fromJava(currentRotation, isXMirrored, isYMirrored));
} else if ((lengthXMirror <= lengthNoMirror) && (lengthXMirror <= lengthYMirror)
&& (lengthXMirror <= lengthXYMirror)) {
currentNode.setOrientation(Orientation.fromJava(currentRotation, !isXMirrored, isYMirrored));
mirrorGain += lengthNoMirror - lengthXMirror;
} else if ((lengthYMirror <= lengthNoMirror) && (lengthYMirror <= lengthXMirror)
&& (lengthYMirror <= lengthXYMirror)) {
currentNode.setOrientation(Orientation.fromJava(currentRotation, isXMirrored, !isYMirrored));
mirrorGain += lengthNoMirror - lengthYMirror;
} else {
mirrorGain += lengthNoMirror - lengthXYMirror;
}
}
}
private void fillEmptyBins() {
// check timeout
if (!checkTimeout())
return;
//
ArrayList<Point2D.Double> emptyBins = new ArrayList<Point2D.Double>();
// find empty bins;
for (int i = 0; i < cellCount.length; i++) {
for (int j = 0; j < cellCount.length; j++) {
if (cellCount[i][j] == 0) {
emptyBins.add(new Point2D.Double((i + 0.5) * Math.sqrt(p.areaPerCell), (j + 0.5)
* Math.sqrt(p.areaPerCell)));
}
}
}
while (checkTimeout()) {
int nodeNumber = (int) (Math.random() * nodesToPlace.size());
int destNumber = (int) (Math.random() * emptyBins.size());
List<PlacementNetwork> currentNetworks = getNetworks(nodesToPlace.get(nodeNumber));
bbPartial.setBenchmarkValues(nodesToPlace, currentNetworks);
double oldMetric = bbPartial.compute();
PlacementNode currentNode = nodesToPlace.get(nodeNumber);
// save old position
double oldX = currentNode.getPlacementX();
double oldY = currentNode.getPlacementY();
currentNode.setPlacement(emptyBins.get(destNumber).x + Math.random() * Math.sqrt(p.areaPerCell),
emptyBins.get(destNumber).y + Math.random() * Math.sqrt(p.areaPerCell));
double newMetric = bbPartial.compute();
boolean overlap = false;
for (int z = 0; z < nodesToPlace.size(); z++) {
if (z != nodeNumber
&& getOverlap(currentNode, nodesToPlace.get(z), new Point2D.Double(0, 0)) != 0) {
overlap = true;
}
}
if (newMetric >= oldMetric || overlap) {
currentNode.setPlacement(oldX, oldY);
}
}
}
private void shakeNodes() {
// check timeout
if (!checkTimeout())
return;
//
double step;
double oldX;
double oldY;
boolean badMove;
double newMetric;
double oldMetric;
int randomDirection;
int nodeNumber;
boolean overlap;
List<PlacementNetwork> currentNetworks;
while (checkTimeout()) {
nodeNumber = (int) (Math.random() * nodesToPlace.size());
currentNetworks = getNetworks(nodesToPlace.get(nodeNumber));
bbPartial.setBenchmarkValues(nodesToPlace, currentNetworks);
oldMetric = bbPartial.compute();
PlacementNode currentNode = nodesToPlace.get(nodeNumber);
step = 1;
badMove = false;
randomDirection = (int) (Math.random() * 8);
while (step >= 1) {
// save old position
oldX = currentNode.getPlacementX();
oldY = currentNode.getPlacementY();
switch (randomDirection) {
case 0:
currentNode.setPlacement(oldX + step, oldY);
break;
case 1:
currentNode.setPlacement(oldX - step, oldY);
break;
case 2:
currentNode.setPlacement(oldX, oldY + step);
break;
case 3:
currentNode.setPlacement(oldX, oldY - step);
break;
case 4:
currentNode.setPlacement(oldX + step, oldY + step);
break;
case 5:
currentNode.setPlacement(oldX + step, oldY - step);
break;
case 6:
currentNode.setPlacement(oldX - step, oldY + step);
break;
case 7:
currentNode.setPlacement(oldX - step, oldY - step);
break;
}
newMetric = bbPartial.compute();
overlap = false;
for (int z = 0; z < nodesToPlace.size(); z++) {
if (z != nodeNumber
&& getOverlap(currentNode, nodesToPlace.get(z), new Point2D.Double(0, 0)) != 0) {
overlap = true;
}
}
if (newMetric >= oldMetric || overlap) {
badMove = true;
currentNode.setPlacement(oldX, oldY);
step = step / 2;
} else {
if (!badMove)
step = step * 2;
oldMetric = newMetric;
}
}
}
}
/**
* Method to find a better position for all of the nodes by swapping nodes.
*/
private void swapNodes() {
// check timeout
if (!checkTimeout())
return;
//
PlacementNode currentNode;
PlacementNode swapNode;
double oldMetric;
double newMetric;
double oldX1;
double oldY1;
double oldX2;
double oldY2;
List<PlacementNetwork> currentNetworks;
for (int i = 0; i < nodesToPlace.size() && checkTimeout(); i++) {
currentNode = nodesToPlace.get(i);
oldX1 = currentNode.getPlacementX();
oldY1 = currentNode.getPlacementY();
for (int j = i + 1; j < nodesToPlace.size() && checkTimeout(); j++) {
swapNode = nodesToPlace.get(j);
currentNetworks = getNetworks(currentNode, swapNode);
bbPartial.setBenchmarkValues(nodesToPlace, currentNetworks);
oldMetric = bbPartial.compute();
oldX2 = swapNode.getPlacementX();
oldY2 = swapNode.getPlacementY();
currentNode.setPlacement(oldX2, oldY2); // swap
swapNode.setPlacement(oldX1, oldY1);
newMetric = bbPartial.compute();
if (newMetric < oldMetric)
continue;
currentNode.setPlacement(oldX1, oldY1); // restore old placement
swapNode.setPlacement(oldX2, oldY2);
}
}
}
// returns set of Networks that are connected to a node
private List<PlacementNetwork> getNetworks(PlacementNode node) {
// use of set to remove duplicates
HashSet<PlacementNetwork> set = new HashSet<PlacementNetwork>();
for (PlacementPort p : node.getPorts()) {
if (p.getPlacementNetwork() != null) {
set.add(p.getPlacementNetwork());
}
}
ArrayList<PlacementNetwork> result = new ArrayList<PlacementNetwork>();
result.addAll(set);
return result;
}
private List<PlacementNetwork> getNetworks(PlacementNode node1, PlacementNode node2) {
// use of set to remove duplicates
HashSet<PlacementNetwork> set = new HashSet<PlacementNetwork>();
for (PlacementPort p : node1.getPorts()) {
if (p.getPlacementNetwork() != null) {
set.add(p.getPlacementNetwork());
}
}
for (PlacementPort p : node2.getPorts()) {
if (p.getPlacementNetwork() != null) {
set.add(p.getPlacementNetwork());
}
}
ArrayList<PlacementNetwork> result = new ArrayList<PlacementNetwork>();
result.addAll(set);
return result;
}
/**
* auxiliary function for getPositionOfPorts
*
* @param placementPort
* @return
*/
private Point2D.Double getAbsolutePositionOf(PlacementPort placementPort) {
return new Point2D.Double(placementPort.getRotatedOffX()
+ placementPort.getPlacementNode().getPlacementX(), placementPort.getRotatedOffY()
+ placementPort.getPlacementNode().getPlacementY());
}
}