/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: GenePlacementLeftRightAlignedDrop.java
* Written by Team 3: Christian Wittner, Ivan Dimitrov
*
* 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.genetic1.g1;
import java.util.ArrayList;
import java.util.Arrays;
import com.sun.electric.tool.placement.genetic1.Chromosome;
import com.sun.electric.tool.placement.genetic1.GenePlacement;
public class GenePlacementLeftRightAlignedDrop implements GenePlacement {
private static int placementWidth = -1;
// private static final boolean DEBUG = false;
int genePosition2Index[];
enum Direction {
LEFT2RIGHT, RIGHT2LEFT
};
Direction direction;
// list of x-,y-coordinates
// first level list secound level int[][0] = x int[][1]=y
int[][] currentLine, previousLine, swapLine;
public GenePlacementLeftRightAlignedDrop(int placementWidth,
int chromosomeSize, PlacementNodeProxy[] nodeProxies) {
this.nodeProxies = nodeProxies;
GenePlacementLeftRightAlignedDrop.placementWidth = placementWidth;
assert (placementWidth != -1);
setChromosomeSize(chromosomeSize);
}
private void setChromosomeSize(int chromosomeSize) {
int assumedLineLength = (int) (Math.sqrt(chromosomeSize) * 1.1);
currentLine = new int[assumedLineLength][];
previousLine = new int[assumedLineLength][];
for (int i = 0; i < assumedLineLength; i++) {
currentLine[i] = new int[2];
previousLine[i] = new int[2];
}
assert (isLineZero(currentLine));
assert (isLineZero(previousLine));
genePosition2Index = new int[chromosomeSize];
}
PlacementNodeProxy[] nodeProxies;
public void placeChromosome(Chromosome chToPlace) {
assert (chToPlace != null);
assert (currentLine != null && previousLine != null) : "set chromsome size before first usage";
assert (placementWidth != -1) : "set placement width before first usage";
assert (chToPlace.isIndex2GenePosValid());
assert (isLineZero(previousLine));
direction = Direction.LEFT2RIGHT;
int tempGenXPosition = 0;
int tempGenYPosition = 0;
int tWidth, tHeight;
int offX = 0;
int positionInCurrentLine = 0;
int startPosition2SearchInPreviousLine = 0;
generateGenePos2IndexMapping(chToPlace.Index2GenePositionInChromosome,
genePosition2Index);
int[] yCalculationResult;
int nodeIndex;
// iterate over all genes we have to place
for (int i = 0; i < genePosition2Index.length; i++) {
// get cell width from placement node proxy and add padding
{
nodeIndex = genePosition2Index[i];
// if we have a gene representing a placement node get width and
// height from placementnodeproxy
tWidth = nodeProxies[nodeIndex].width + chToPlace.GeneXPadding[nodeIndex];
tHeight = nodeProxies[nodeIndex].height+ chToPlace.GeneYPadding[nodeIndex];
// if gene is rotated sideways swap width and height
if (chToPlace.GeneRotation[nodeIndex] == 900
|| chToPlace.GeneRotation[nodeIndex] == 2700) {
int swap = tHeight;
tHeight = tWidth;
tWidth = swap;
}
}
// as we positions genes' center we need to use half width and
// height
tWidth = tWidth >> 1;
tHeight = tHeight >> 1;
// calculate x position
// if going left to right add to the x offset
if (direction == Direction.LEFT2RIGHT)
tempGenXPosition = offX + tWidth;
else
// if going right to left subtract from x offset
tempGenXPosition = offX - tWidth;
// cell doesn't fit current line start new one
if (direction == Direction.LEFT2RIGHT
&& (tempGenXPosition + tWidth) > placementWidth) {
// identical for both line switches
{
swapLine = currentLine;
currentLine = previousLine;
previousLine = swapLine;
assert (isLineInXOrder(previousLine,
positionInCurrentLine - 1, direction));
// remember until which position the current line was used
// to
// store valid y values
startPosition2SearchInPreviousLine = positionInCurrentLine;
positionInCurrentLine = 0;
}
// unique for left2rigth
{
// switch to right2left
direction = Direction.RIGHT2LEFT;
offX = placementWidth;
tempGenXPosition = placementWidth - tWidth;
}
} else if (direction == Direction.RIGHT2LEFT
&& (tempGenXPosition - tWidth) < 0) {
// identical for both line switches
{
swapLine = currentLine;
currentLine = previousLine;
previousLine = swapLine;
assert (isLineInXOrder(previousLine,
positionInCurrentLine - 1, direction));
// remember until which position the current line was used
// to
// store valid y values
startPosition2SearchInPreviousLine = positionInCurrentLine;
positionInCurrentLine = 0;
}
// unique for left2rigth
{
// switch to left2right
direction = Direction.LEFT2RIGHT;
offX = 0;
tempGenXPosition = tWidth;
}
}
tWidth = tWidth << 1;
// calculate y value for center of current cell to place
if (direction == Direction.LEFT2RIGHT) {
yCalculationResult = calculateY(offX, offX + tWidth, tHeight,
startPosition2SearchInPreviousLine, direction);
} else {
yCalculationResult = calculateY(offX, offX - tWidth, tHeight,
startPosition2SearchInPreviousLine, direction);
}
tempGenYPosition = yCalculationResult[1];
startPosition2SearchInPreviousLine = yCalculationResult[0];
// store the yValue at to of the current cell as contour reference
// line for
// the next loop
if (direction == Direction.LEFT2RIGHT)
storeYValue(positionInCurrentLine, tempGenYPosition + tHeight,
offX, offX + tWidth);
else
storeYValue(positionInCurrentLine, tempGenYPosition + tHeight,
offX, offX - tWidth);
chToPlace.GeneXPos[nodeIndex] = tempGenXPosition;
chToPlace.GeneYPos[nodeIndex] = tempGenYPosition;
if (direction == Direction.LEFT2RIGHT)
offX += tWidth;
else
offX -= tWidth;
positionInCurrentLine++;
}
// clear previous line for next use
for (int i = 0; i < previousLine.length; i++) {
previousLine[i][0] = 0;
previousLine[i][1] = 0;
}
}
/**
* As the chromosome stores the position of a given index in an array in
* index order this method converts it into an array in gene position order
* pointing to the indexes.
*
* @param index2GenePositionInChromosome
* Array in index order. (first entry is position of node with
* index 0)
*
* @param returnValueGenerateGenePos2IndexMapping
* Reference to the array to store the return value. The gene
* position to index map.
*/
public static void generateGenePos2IndexMapping(
int[] index2GenePositionInChromosome,
int[] returnValueGenerateGenePos2IndexMapping) {
assert (index2GenePositionInChromosome.length == returnValueGenerateGenePos2IndexMapping.length);
for (int index = 0; index < index2GenePositionInChromosome.length; index++)
returnValueGenerateGenePos2IndexMapping[index2GenePositionInChromosome[index]] = index;
}
private boolean isLineInXOrder(int[][] previousLine, int linePosition,
Direction direction) {
if (direction == Direction.LEFT2RIGHT)
for (int i = 0; i < linePosition; i++) {
assert (previousLine[i][0] <= placementWidth && previousLine[i][0] >= 0);
if (previousLine[i][0] >= previousLine[i + 1][0])
return false;
}
else
for (int i = 0; i < linePosition; i++) {
assert (previousLine[i][0] <= placementWidth && previousLine[i][0] >= 0);
if (previousLine[i][0] <= previousLine[i + 1][0])
return false;
}
return true;
}
/**
* Calculates y-value for the center of the current block to place depending
* on the previously stored contour line.
*
*
* @param startX
* x position at the beginning of the block to place
* @param endX
* x position at the end of the block to place
* @param halfCellHeigth
* half the height of the block to place
* @param startPosition2SearchInPreviousLine
* position to start searching for the y-value in the previous
* line.
* @param direction
* direction telling if placement is currently left to right or
* right to left.
*
* @return int[] with int[0] = new start position for next search. int[1] =
* calculated y value for current block.
*/
private int[] calculateY(int startX, int endX, int halfCellHeigth,
int startPosition2SearchInPreviousLine, Direction direction) {
int yValue = 0;
int newSearchStartPosition = -1;
// initialize for the case that our current block is on the height of
// the starting block of the previous line
int valueBeforeInterval = previousLine[startPosition2SearchInPreviousLine][1];
int valueAfterInterval = previousLine[0][1];
// will be true if a value between startX and endX is present in the
// previous line
boolean valueInRange = false;
// find highest y between startX and endX in previous Line
// have to step through it backward as we move in opposite direction
// when placing
// a line relative to it's previous line.
int curY, curX;
for (int pos = startPosition2SearchInPreviousLine; pos >= 0; pos--) {
curY = previousLine[pos][1];
curX = previousLine[pos][0];
// store value before interval
if (!valueInRange) {
valueAfterInterval = valueBeforeInterval = curY;
newSearchStartPosition = pos;
}
// if x value in previousLine is passed exit
if (direction == Direction.LEFT2RIGHT && curX > endX
|| direction == Direction.RIGHT2LEFT && curX < endX) {
valueAfterInterval = curY;
break;
}
// search for highest yValue within range of previous Line
if (direction == Direction.LEFT2RIGHT) {
if (curX > startX) {
valueInRange = true;
newSearchStartPosition = pos;
if (curY > yValue) {
yValue = curY;
}
}
} else {
if (curX < startX) {
valueInRange = true;
newSearchStartPosition = pos;
if (curY > yValue) {
yValue = curY;
}
}
}
}
assert (valueAfterInterval >= 0);
if (!valueInRange)
yValue = Math.min(valueBeforeInterval, valueAfterInterval);
yValue += halfCellHeigth;
return new int[] { newSearchStartPosition, yValue };
}
private boolean isLineZero(int[][] line) {
for (int[] p : line) {
if (p[0] != 0 || p[1] != 0)
return false;
}
return true;
}
/**
* For current line store the height of the current block.
*
* @param currentLine
* @param positionInLine
* @param topyValue
* Y value of top of the current cell.
* @param startX
* X-value where current block starts.
* @param endX
* X-value where current block ends.
*/
private void storeYValue(int positionInLine, int topyValue, int startX,
int endX) {
// if currentLine to short to store value add new point
// intense but should rarely happen. best if it never happens but still
// better than an index out of bounds exception
if (currentLine.length <= positionInLine + 1) {
ArrayList<int[]> expansionHelper = new ArrayList<int[]>(
currentLine.length + 5);
expansionHelper.addAll(Arrays.asList(currentLine));
// grow by 5 slots
for (int i = 0; i < 5; i++)
expansionHelper.add(new int[2]);
currentLine = expansionHelper.toArray(new int[expansionHelper
.size()][]);
}
// for first cell in line just store yValue at startX
if (positionInLine == 0) {
currentLine[positionInLine][0] = startX;
currentLine[positionInLine][1] = topyValue;
} else {
// see if yValue at the beginning of the block is smaller than
// yValue if so set it to Y
if (currentLine[positionInLine][1] < topyValue)
currentLine[positionInLine][1] = topyValue;
}
assert (currentLine[positionInLine][0] == startX);
// store YValue at endX
currentLine[positionInLine + 1][0] = endX;
currentLine[positionInLine + 1][1] = topyValue;
}
}