/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: PlacementSimulatedAnnealingRowCol.java
* Written by Team 6: Sebastian Roether, Jochen Lutz
* Rewritten for column/row placement by Steven M. Rubin
*
* 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.simulatedAnnealing3;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.tool.placement.PlacementFrame;
import com.sun.electric.util.math.Orientation;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
/**
* Implementation of the simulated annealing placement algorithm for row/column placement.
*/
public class PlacementSimulatedAnnealingRowCol extends PlacementFrame
{
// parameters
private PlacementParameter numThreadsParam = new PlacementParameter("threads",
"Number of threads:", Runtime.getRuntime().availableProcessors());
private PlacementParameter maxRuntimeParam = new PlacementParameter("runtime",
"Runtime (in seconds, 0 for no limit):", 240);
private static final int PLACEMENTSTYLE_COLUMNS = 0;
// private static final int PLACEMENTSTYLE_ROWS = 1;
private PlacementParameter placementStyleParam = new PlacementParameter("placementStyle",
"Placement style:", 0, new String[] {"Column-based Placement", "Row-based Placement"});
private PlacementParameter flipAlternateColsRows = new PlacementParameter("flipColRow",
"Column/row placement: flip alternate columns/rows", true);
private PlacementParameter makeStacksEven = new PlacementParameter("makeStacksEven",
"Force rows/columns to be equal length", true);
// Temperature control
/** current "temperature" for allowing bad moves */ private double temperature;
/** starting time of run (for termination and temp changes) */ private long timestampStart;
/** number of moves per iteration of algorithm */ private int stepsPerUpdate;
/** number of temperature steps before completion */ private int numTemperatureSteps;
/** number of temperature steps completed so far */ private int numStepsDone;
/** list of proxy nodes */ private List<ProxyNode> nodesToPlace;
/** map from original PlacementNodes to proxy nodes */ private Map<PlacementNode, ProxyNode> proxyMap;
/** true if doing column placement */ private boolean columnPlacement;
/** number of stacks of cells */ private int numStacks;
/** the contents of the stacks */ private List<ProxyNode>[] stackContents;
/** the height (of columns) or width (of rows) */ private double[] stackSizes;
/** X coordinates (of columns) or Y coordinates (of rows) */ private double[] stackCoords;
/** indicator of stack usage in a thread */ private boolean[] stacksBusy;
/** for statistics gathering */ private int better, worse, worseAccepted;
/** global random object */ private Random randNum = new Random();
/**
* Method to return the name of this placement algorithm.
* @return the name of this placement algorithm.
*/
public String getAlgorithmName() { return "Simulated-Annealing-Row/Col"; }
/**
* Method to do placement by simulated annealing.
* @param placementNodes 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> placementNodes, List<PlacementNetwork> allNetworks, String cellName)
{
columnPlacement = placementStyleParam.getIntValue() == PLACEMENTSTYLE_COLUMNS;
// create proxies for placement nodes and insert in lists and maps
nodesToPlace = new ArrayList<ProxyNode>(placementNodes.size());
proxyMap = new HashMap<PlacementNode, ProxyNode>();
Set<Double> girths = new HashSet<Double>();
for (PlacementNode p : placementNodes)
{
ProxyNode proxy = new ProxyNode(p);
double girth = proxy.getCellGirth();
girths.add(new Double(girth));
nodesToPlace.add(proxy);
proxyMap.put(p, proxy);
}
// warn if the girths are uneven
if (girths.size() != 1)
{
StringBuffer sb = new StringBuffer();
for(Double girth : girths)
sb.append(" " + girth);
System.out.println("WARNING: Stacks have uneven girth:" + sb.toString());
}
// create an initial layout to be improved by simulated annealing
initLayout();
// make sure there aren't too many threads
int threadCount = numThreadsParam.getIntValue();
if (threadCount >= numStacks/2)
{
threadCount = numStacks/2-1;
System.out.println("Note: Using only " + threadCount + " threads");
}
setParamterValues(threadCount, maxRuntimeParam.getIntValue());
// initialize temperature
stepsPerUpdate = (int)Math.sqrt(nodesToPlace.size());
temperature = 2000.0;
numTemperatureSteps = countTemperatureSteps(temperature);
numStepsDone = 0;
timestampStart = System.currentTimeMillis();
// initialize statistics
better = worse = worseAccepted = 0;
// start the Simulated Annealing threads
SimulatedAnnealing[] threads = new SimulatedAnnealing[numOfThreads];
for (int n = 0; n < numOfThreads; n++)
{
threads[n] = new SimulatedAnnealing();
threads[n].start();
}
// wait for the threads to finish
for (int i = 0; i < numOfThreads; i++)
{
try
{
threads[i].join();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
if (makeStacksEven.getBooleanValue())
{
// even the stacks as much as possible
evenAllStacks(allNetworks);
}
// apply the placement of the proxies to the actual nodes
for (PlacementNode pn : placementNodes)
{
ProxyNode p = proxyMap.get(pn);
pn.setPlacement(p.getPlacementX(), p.getPlacementY());
pn.setOrientation(p.getPlacementOrientation());
}
// show results
DecimalFormat formater = new DecimalFormat("###,###,###");
String betterStr = formater.format(better);
String worseStr = formater.format(worse);
String worseAcceptedStr = formater.format(worseAccepted);
System.out.println("Made " + betterStr + " moves that improve results, " +
worseStr + " moves that worsened it (and " + worseAcceptedStr + " were accepted)");
}
private void evenAllStacks(List<PlacementNetwork> allNetworks)
{
boolean [] stackConsidered = new boolean[numStacks];
for(;;)
{
// find initial network length
double initialLength = netLength(allNetworks);
int bestOtherStack = -1;
int placeInOtherStack = -1;
double bestGain = 0;
ProxyNode nodeToMove = null;
for(int i=0; i<numStacks; i++) stackConsidered[i] = false;
// now look at all tall stacks and find something that can be moved out of them
for(;;)
{
// find tallest stack that hasn't already been considered
int tallestStack = -1;
for(int i=0; i<numStacks; i++)
{
if (stackConsidered[i]) continue;
if (tallestStack < 0 || stackSizes[i] > stackSizes[tallestStack])
tallestStack = i;
}
if (tallestStack < 0) break;
stackConsidered[tallestStack] = true;
// look at all nodes in the tall stack
for(ProxyNode pn : stackContents[tallestStack])
{
double size = pn.getCellSize();
// find another stack in which this node could go to even the sizes
for(int i=0; i<numStacks; i++)
{
if (i == tallestStack) continue;
if (stackSizes[i] + size > stackSizes[tallestStack] - size) continue;
// could go in this stack: look for the best place for it
for(int j=0; j<stackContents[i].size(); j++)
{
proposeMove(pn, tallestStack, i, j);
double proposedLength = 0;
for(PlacementNetwork net : allNetworks)
proposedLength += netLength(net, tallestStack, i);
double gain = initialLength - proposedLength;
if (gain > bestGain)
{
bestOtherStack = i;
placeInOtherStack = j;
bestGain = gain;
nodeToMove = pn;
}
}
}
}
if (bestGain > 0)
{
// make the move
proposeMove(nodeToMove, tallestStack, bestOtherStack, placeInOtherStack);
implementMove(nodeToMove, tallestStack, bestOtherStack, placeInOtherStack);
break;
}
}
if (bestGain == 0) break;
}
}
/**
* Method that generates an initial node placement.
*/
private void initLayout()
{
double totalSize = 0;
double maxGirth = 0;
for(ProxyNode plNode : nodesToPlace)
{
totalSize += plNode.getCellSize();
maxGirth = Math.max(maxGirth, plNode.getCellGirth());
}
double avgCellSize = totalSize / nodesToPlace.size();
double avgStackSize = Math.sqrt(totalSize * maxGirth);
numStacks = (int)Math.round(totalSize / avgStackSize);
int numPerStack = (int)Math.ceil(nodesToPlace.size() / (double)numStacks);
stackCoords = new double[numStacks];
stackContents = new List[numStacks];
stackSizes = new double[numStacks];
stacksBusy = new boolean[numStacks];
for(int i=0; i<numStacks; i++)
{
stackContents[i] = new ArrayList<ProxyNode>();
stackSizes[i] = 0;
stacksBusy[i] = false;
}
double girthPos = -maxGirth;
double stackPos = 0;
int stackIndex = -1;
for (int i = 0; i < nodesToPlace.size(); i++)
{
if ((i % numPerStack) == 0)
{
girthPos += maxGirth;
stackIndex++;
stackPos = 0;
stackCoords[stackIndex] = girthPos;
}
ProxyNode plNode = nodesToPlace.get(i);
Orientation o = getOrientation(stackIndex);
if (columnPlacement) plNode.setPlacement(girthPos, stackPos, stackIndex, o, true); else
plNode.setPlacement(stackPos, girthPos, stackIndex, o, true);
stackPos += avgCellSize;
List<ProxyNode> pnList = stackContents[stackIndex];
stackSizes[stackIndex] += plNode.getCellSize();
pnList.add(plNode);
}
for(int i=0; i<numStacks; i++)
{
List<ProxyNode> pnList = stackContents[i];
Collections.sort(pnList);
evenStack(i);
}
}
/**
* Method that counts how often the temperature will be decreased before going below 1.
*/
private int countTemperatureSteps(double startingTemperature)
{
double temp = startingTemperature;
int steps = 0;
while (temp > 1)
{
steps++;
temp = coolDown(temp);
}
return steps;
}
/**
* Method to calculate the cooling of the simulated annealing process.
* @param temp the current temperature
* @return the lowered temperature
*/
private double coolDown(double temp)
{
return temp * 0.99 - 0.1;
}
private Orientation getOrientation(int index)
{
Orientation o = Orientation.IDENT;
if (flipAlternateColsRows.getBooleanValue() && (index%2) != 0)
{
if (columnPlacement) return Orientation.X;
return Orientation.Y;
}
return o;
}
/**
* Class that does the actual simulated annealing. All instances of this
* class share the same data set. Simulated annealing goes like this:
*
* - find a measure of how good a placement is (the total net length)
* - define a "starting temperature"
* - given a placement, do something that could change this measure
* (move nodes or swap them)
* - if the measure is better, fine. If not the probability of accepting this
* depends on the temperature and on how much the placement is worse than
* before. The higher the temperature, the higher the probability of bad
* moves being accepted
* - decrease temperature
* - repeat until temperature reaches 0
*
* The effects of this implementations are:
* - The less likely it is that a move is accepted, the better the speedup
* - The more threads started, the more likely it is moves are conflicting when
* accepted because they work with the same data
* - starting more threads than there are cores is most likely useless (?)
*/
class SimulatedAnnealing extends Thread
{
Random rand = new Random();
public void run()
{
// Thread wont stop until temperature is below 1
while (temperature > 1)
{
// Try some perturbations before checking if temperature has to be lowered
for (int step = 0; step < stepsPerUpdate; step++)
{
// decide whether to work in two stacks or one
ProxyNode node = null;
int oldIndex, newIndex;
int r = rand.nextInt(numStacks);
if (r == 0)
{
// work within one stack
for(;;)
{
oldIndex = lockRandomStack();
if (oldIndex < 0) continue;
if (stackContents[oldIndex].size() <= 1) { releaseStack(oldIndex); continue; }
break;
}
newIndex = oldIndex;
node = getRandomNode(oldIndex);
} else
{
// work between two stacks
for(;;)
{
oldIndex = lockRandomStack();
if (oldIndex < 0) continue;
newIndex = lockRandomStack();
if (newIndex < 0) { releaseStack(oldIndex); continue; }
// cannot play with stacks that are nearly empty
if (stackContents[oldIndex].size() <= 1 && stackContents[newIndex].size() <= 1)
{
releaseStack(oldIndex);
releaseStack(newIndex);
continue;
}
break;
}
node = getRandomNode(oldIndex);
// swap stacks if it makes the lengths become more uniform
boolean doSwap = stackSizes[newIndex] > stackSizes[oldIndex];
// // do not swap stacks during the first 75% of the time
// if (numStepsDone < numTemperatureSteps * 3 / 4) doSwap = false;
//
// // do force swap to prevent zero-size stacks
// if (stackContents[oldIndex].size() <= 1) doSwap = true;
// swap if requested
if (doSwap)
{
int swap = oldIndex; oldIndex = newIndex; newIndex = swap;
node = getRandomNode(oldIndex);
}
}
int newPlaceInStack = rand.nextInt(stackContents[newIndex].size()+1);
if (newIndex == oldIndex)
{
if (stackContents[newIndex].size() >= 2)
{
while(newPlaceInStack < stackContents[newIndex].size())
{
if (stackContents[newIndex].get(newPlaceInStack) != node &&
(newPlaceInStack == 0 || stackContents[newIndex].get(newPlaceInStack-1) != node)) break;
newPlaceInStack = rand.nextInt(stackContents[newIndex].size()+1);
}
}
int oldPlaceInStack = stackContents[oldIndex].indexOf(node);
if (oldPlaceInStack < newPlaceInStack) newPlaceInStack--;
}
// determine the network length before the move
double networkMetricBefore = 0;
for(PlacementNetwork net : node.getNets())
networkMetricBefore += netLength(net, -1, -1);
// make the move (set in temporary "proposed" variables)
proposeMove(node, oldIndex, newIndex, newPlaceInStack);
// determine the network length after the move
double networkMetricAfter = 0;
for (PlacementNetwork net : node.getNets())
networkMetricAfter += netLength(net, newIndex, oldIndex);
// the worse the gain of a perturbation, the lower the probability that this perturbation
// is actually applied (positive gains are always accepted)
double gain = networkMetricBefore - networkMetricAfter;
if (gain < 0) worse++; else better++;
if (gain > 0 || Math.exp(gain / temperature) >= Math.random())
{
if (gain < 0) worseAccepted++;
implementMove(node, oldIndex, newIndex, newPlaceInStack);
}
releaseStack(oldIndex);
if (newIndex != oldIndex) releaseStack(newIndex);
}
update();
}
}
}
/**
* Method that does temperature and time control. Threads
* should call this periodically.
*/
private void update()
{
// adjust how many moves to try before the next temperature decrease
if (runtime > 0)
{
// use the time to calculate new temperature
long elapsedTime = System.currentTimeMillis() - timestampStart;
double fractionDone = elapsedTime / (runtime * 1000.0);
int stepsToDo = (int)(numTemperatureSteps * fractionDone);
for( ; numStepsDone < stepsToDo; numStepsDone++)
temperature = coolDown(temperature);
} else
{
temperature = coolDown(temperature);
}
}
private void implementMove(ProxyNode node, int oldIndex, int newIndex, int newPlaceInStack)
{
remove(node);
node.setPlacement(node.getProposedX(), node.getProposedY(), node.getProposedIndex(),
getOrientation(node.getProposedIndex()), true);
put(node, newIndex, newPlaceInStack);
evenStack(oldIndex);
if (newIndex != oldIndex) evenStack(newIndex);
}
private void proposeMove(ProxyNode node, int oldIndex, int newIndex, int newPlaceInStack)
{
Orientation newOrient = getOrientation(newIndex);
if (oldIndex != newIndex)
{
// set proposed locations in the old stack without the moved node
double bottom = 0;
List<ProxyNode> pnList = stackContents[oldIndex];
for(ProxyNode pn : pnList)
{
if (pn == node) continue;
double x = pn.getPlacementX();
double y = pn.getPlacementY();
double size = pn.getCellSize();
if (columnPlacement) y = bottom + size/2; else
x = bottom + size/2;
bottom += size;
pn.setProposed(x, y, pn.getColumnRowIndex(), pn.getPlacementOrientation());
}
// set proposed locations in the new stack with the moved node
bottom = 0;
boolean notInserted = true;
List<ProxyNode> newList = stackContents[newIndex];
for(int i=0; i<newList.size(); i++)
{
ProxyNode pn = newList.get(i);
Orientation o = pn.getPlacementOrientation();
double x = pn.getPlacementX();
double y = pn.getPlacementY();
if (notInserted && i == newPlaceInStack)
{
if (columnPlacement) x = stackCoords[newIndex]; else
y = stackCoords[newIndex];
pn = node;
o = newOrient;
i--;
notInserted = false;
}
double size = pn.getCellSize();
if (columnPlacement) y = bottom + size/2; else
x = bottom + size/2;
bottom += size;
pn.setProposed(x, y, newIndex, o);
}
if (notInserted)
{
double size = node.getCellSize();
if (columnPlacement)
node.setProposed(stackCoords[newIndex], bottom + size/2, newIndex, newOrient); else
node.setProposed(bottom + size/2, stackCoords[newIndex], newIndex, newOrient);
}
} else
{
// redo the new stack with the moved node
double bottom = 0;
boolean notInserted = true;
for(int i=0; i<stackContents[newIndex].size(); i++)
{
ProxyNode pn = stackContents[newIndex].get(i);
if (pn == node) continue;
if (notInserted && i == newPlaceInStack)
{
pn = node;
i--;
notInserted = false;
}
double x = pn.getPlacementX();
double y = pn.getPlacementY();
double size = pn.getCellSize();
if (columnPlacement) y = bottom + size/2; else
x = bottom + size/2;
bottom += size;
pn.setProposed(x, y, newIndex, pn.getPlacementOrientation());
}
if (notInserted)
{
double size = node.getCellSize();
if (columnPlacement)
node.setProposed(node.getPlacementX(), bottom + size/2, newIndex, newOrient); else
node.setProposed(bottom + size/2, node.getPlacementY(), newIndex, newOrient);
}
}
}
private synchronized int lockRandomStack()
{
int index = randNum.nextInt(numStacks);
for(int i=0; i<numStacks; i++)
{
if (!stacksBusy[index])
{
stacksBusy[index] = true;
return index;
}
index = (index+1) % numStacks;
}
return -1;
}
private void releaseStack(int index)
{
stacksBusy[index] = false;
}
/**
* Method that approximates the conductor length of a set of nets when proxies are used
* @param networks the PlacementNetworks to analyze.
* @return the length of the connections on the networks.
*/
private double netLength(List<PlacementNetwork> networks)
{
double length = 0;
for(PlacementNetwork net : networks)
length += netLength(net, -1, -1);
return length;
}
/**
* Method that calculates the bounding box net length approximation for a given net.
* It hashes the nodes of the ports in the nets to its proxies.
* Also, it may substitute a node with another one just for this calculation
* @param net the PlacementNetwork to analyze.
* @param workingIndex1 a stack number that is being "proposed".
* @param workingIndex1 another stack number that is being "proposed".
* @return the length of the connections on the network.
*/
private double netLength(PlacementNetwork net, int workingIndex1, int workingIndex2)
{
double minX = Double.MAX_VALUE, minY = Double.MAX_VALUE, maxX = -Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
for (PlacementPort port : net.getPortsOnNet())
{
ProxyNode pn = proxyMap.get(port.getPlacementNode());
double currX, currY;
Orientation o;
if (pn.getColumnRowIndex() == workingIndex1 || pn.getColumnRowIndex() == workingIndex2)
{
currX = pn.getProposedX();
currY = pn.getProposedY();
o = pn.getProposedOrientation();
} else
{
currX = pn.getPlacementX();
currY = pn.getPlacementY();
o = pn.getPlacementOrientation();
}
if (o == Orientation.X) currX -= port.getOffX(); else
currX += port.getOffX();
if (o == Orientation.Y) currY -= port.getOffY(); else
currY += port.getOffY();
if (currX < minX) minX = currX;
if (currX > maxX) maxX = currX;
if (currY < minY) minY = currY;
if (currY > maxY) maxY = currY;
}
return (maxX - minX) + (maxY - minY);
}
/**
* Method that finds a random ProxyNode in a specific stack.
* @param index the stack index.
* @return a random ProxyNode.
*/
private ProxyNode getRandomNode(int index)
{
List<ProxyNode> pnList = stackContents[index];
return pnList.get(randNum.nextInt(pnList.size()));
}
/**
* Adds a node to the stack lists.
* @param node the ProxyNode to add to the stack lists.
*/
private void put(ProxyNode node, int index, int position)
{
List<ProxyNode> pnList = stackContents[index];
pnList.add(position, node);
stackSizes[index] += node.getCellSize();
}
/**
* Removes a node from all stack lists.
* @param node the ProxyNode to remove.
*/
private void remove(ProxyNode node)
{
int index = node.getColumnRowIndex();
List<ProxyNode> pnList = stackContents[index];
if (!pnList.remove(node))
{
System.out.println("ERROR: could not remove node from stack "+index);
}
stackSizes[index] -= node.getCellSize();
}
/**
* Method to rearrange a stack so that all cells touch.
* @param index the stack index.
*/
private void evenStack(int index)
{
double bottom = 0;
List<ProxyNode> pnList = stackContents[index];
for(ProxyNode pn : pnList)
{
double x = pn.getPlacementX();
double y = pn.getPlacementY();
double size = pn.getCellSize();
if (columnPlacement) y = bottom + size/2; else
x = bottom + size/2;
bottom += size;
pn.setPlacement(x, y, index, pn.getPlacementOrientation(), true);
}
}
/*************************************** Proxy Node **********************************/
/**
* This class is a proxy for the actual PlacementNode.
* It can be moved around and rotated without touching the actual PlacementNode.
*/
class ProxyNode implements Comparable<ProxyNode>
{
private double x, y; // current location
private double newX, newY; // proposed location when testing rearrangement
private int index; // stack number (row or column)
private int proposedIndex; // proposed stack number (row or column)
private Orientation orientation; // orientation of the placement node
private Orientation proposedOrientation; // proposed orientation
private double width = 0; // width of the placement node
private double height = 0; // height of the placement node
private List<PlacementNetwork> nets = new ArrayList<PlacementNetwork>();
/**
* Constructor to create a ProxyNode
* @param node the PlacementNode that should is being shadowed.
*/
public ProxyNode(PlacementNode node)
{
x = node.getPlacementX();
y = node.getPlacementY();
NodeProto np = ((com.sun.electric.tool.placement.PlacementAdapter.PlacementNode)node).getType();
Rectangle2D spacing = null;
if (np instanceof Cell)
{
spacing = ((Cell)np).findEssentialBounds();
}
if (spacing == null)
{
width = node.getWidth();
height = node.getHeight();
} else
{
width = spacing.getWidth();
height = spacing.getHeight();
}
// create a list of all nets that node belongs to
for(PlacementPort p : node.getPorts())
{
if (!nets.contains(p.getPlacementNetwork()) && p.getPlacementNetwork() != null)
nets.add(p.getPlacementNetwork());
}
orientation = node.getPlacementOrientation();
}
public void setProposed(double x, double y, int ind, Orientation o)
{
newX = x;
newY = y;
proposedIndex = ind;
proposedOrientation = o;
}
/**
* Method to get the proposed X-coordinate of this ProxyNode.
* @return the proposed X-coordinate of this ProxyNode.
*/
public double getProposedX() { return newX; }
/**
* Method to get the proposed Y-coordinate of this ProxyNode.
* @return the proposed Y-coordinate of this ProxyNode.
*/
public double getProposedY() { return newY; }
/**
* Method to get the proposed stack index of this ProxyNode.
* @return the proposed stack index of this ProxyNode.
*/
public int getProposedIndex() { return proposedIndex; }
/**
* Method to get the proposed orientation of this ProxyNode.
* @return the proposed orientation of this ProxyNode.
*/
public Orientation getProposedOrientation() { return proposedOrientation; }
/**
* Method that sets the node to a new position.
* @param x the X coordinate.
* @param y the Y coordinate.
* @param ind the column/row index.
*/
public void setPlacement(double x, double y, int ind, Orientation o, boolean check)
{
if (check)
{
double req = stackCoords[ind];
if (columnPlacement)
{
if (x != req)
System.out.println("Moving node from ("+this.x+"["+this.index+"],"+this.y+") to ("+x+"["+ind+"],"+y+") BUT STACK "+ind+" IS AT "+req);
} else
{
if (y != req)
System.out.println("Moving node from ("+this.x+","+this.y+"["+this.index+"]) to ("+x+","+y+"["+ind+"]) BUT STACK "+ind+" IS AT "+req);
}
Orientation oReq = getOrientation(ind);
if (o != oReq)
System.out.println("Rotating node from ("+this.x+","+this.y+")[S="+this.index+" O="+orientation.toString()+
"] to ("+x+","+y+")[S="+ind+" O="+o.toString()+"] BUT O SHOULD BE '"+oReq.toString()+"'");
}
this.x = x;
this.y = y;
index = ind;
orientation = o;
}
/**
* Method that returns the column or row number, when doing column/row-based placement.
* @return the column/row index.
*/
public int getColumnRowIndex() { return index; }
/**
* Method to get a list of nets this node belongs to.
* This is more convenient than iterating over the ports.
* Also it only contains nets that are not ignored (e.g. because they are too huge).
* @return the list of nets this node belongs to.
*/
public List<PlacementNetwork> getNets() { return nets; }
/**
* Method to get the X-coordinate of this ProxyNode.
* @return the X-coordinate of this ProxyNode.
*/
public double getPlacementX() { return x; }
/**
* Method to get the Y-coordinate of this ProxyNode.
* @return the Y-coordinate of this ProxyNode.
*/
public double getPlacementY() { return y; }
/**
* Method to get the width of this ProxyNode.
* @return the width of this ProxyNode.
*/
public double getWidth() { return width; }
/**
* Method to get the height of this ProxyNode.
* @return the height of this ProxyNode.
*/
public double getHeight() { return height; }
/**
* Method to get the size of this ProxyNode along the stack dimension.
* For column-based placement, this is the height;
* for row-based placement, this is the width;
* @return the size of this ProxyNode.
*/
public double getCellSize()
{
if (columnPlacement) return height;
return width;
}
/**
* Method to get the girth of this ProxyNode, which separation of the stacks.
* For column-based placement, this is the width;
* for row-based placement, this is the height;
* @return the girth of this ProxyNode.
*/
public double getCellGirth()
{
if (columnPlacement) return width;
return height;
}
/**
* Method to get the orientation of this ProxyNode.
* @return the orientation of this ProxyNode.
*/
public Orientation getPlacementOrientation() { return orientation; }
public int compareTo(ProxyNode o)
{
if (columnPlacement)
{
double y1 = getPlacementY();
double y2 = o.getPlacementY();
if (y1 < y2) return 1;
if (y1 > y2) return -1;
} else
{
double x1 = getPlacementX();
double x2 = o.getPlacementX();
if (x1 < x2) return 1;
if (x1 > x2) return -1;
}
return 0;
}
}
}