/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: StratSizes.java
*
* Copyright (c) 2003, 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.ncc.strategy;
import java.util.Iterator;
import com.sun.electric.tool.ncc.NccGlobals;
import com.sun.electric.tool.ncc.lists.LeafList;
import com.sun.electric.tool.ncc.netlist.Mos;
import com.sun.electric.tool.ncc.netlist.NetObject;
import com.sun.electric.tool.ncc.netlist.Part;
import com.sun.electric.tool.ncc.netlist.Resistor;
import com.sun.electric.tool.ncc.trees.Circuit;
import com.sun.electric.tool.ncc.trees.EquivRecord;
/** The OutlierTrans for each Circuit in the EquivRecord */
class OutlierRecord {
/** The Part in the Circuit that is most different from the others */
private static class Outlier {
public final Part part;
public final double deviation;
Outlier(Part p, double diff) {part=p; deviation=diff;}
}
private final Part[] parts;
private final double deviation;
private boolean hasSize(Part p) {
return p instanceof Resistor || p instanceof Mos;
}
private double getWidth(Part p) {
if (p instanceof Resistor) {
return ((Resistor)p).getWidth();
} else {
return ((Mos)p).getWidth();
}
}
private double getLength(Part p) {
if (p instanceof Resistor) {
return ((Resistor)p).getLength();
} else {
return ((Mos)p).getLength();
}
}
private double[] computeAverageWidthLength(Circuit c) {
double totLen=0, totWid=0;
for (Iterator<NetObject> it=c.getNetObjs(); it.hasNext();) {
Part p = (Part) it.next();
totLen += getLength(p);
totWid += getWidth(p);
}
int numParts = c.numNetObjs();
return new double[] {totWid/numParts, totLen/numParts};
}
private double computeWidthLengthDeviation(double avgWid, double avgLen, Part p) {
double deltaW = (getWidth(p)-avgWid) / avgWid;
double deltaL = (getLength(p)-avgLen) / avgLen;
return Math.abs(deltaW) + Math.abs(deltaL);
}
private double computeWidthLengthMismatch(Part p1, Part p2) {
double w1 = getWidth(p1);
double l1 = getLength(p1);
double w2 = getWidth(p2);
double l2 = getLength(p2);
double avgW = (w1+w2)/2;
double avgL = (l1+l2)/2;
return Math.abs((w1-w2)/avgW) + Math.abs((l1-l2)/avgL);
}
private Outlier findOutlier(Circuit c) {
if (!hasSize((Part)c.getNetObjs().next()))
return new Outlier(null, 0);
double[] avgWidLen = computeAverageWidthLength(c);
double avgWid = avgWidLen[0];
double avgLen = avgWidLen[1];
Part worstPart = null;
double worstDeviation = 0;
for (Iterator<NetObject> it=c.getNetObjs(); it.hasNext();) {
Part p = (Part) it.next();
double deviation = computeWidthLengthDeviation(avgWid, avgLen, p);
if (deviation>worstDeviation) {
worstPart = p;
worstDeviation = deviation;
}
}
return new Outlier(worstPart, worstDeviation);
}
private Part findClosestSizedPart(Circuit c, Part outlier) {
Part bestPart = null;
double bestMismatch = Double.MAX_VALUE;
for (Iterator<NetObject> it=c.getNetObjs(); it.hasNext();) {
Part p = (Part) it.next();
double mismatch = computeWidthLengthMismatch(outlier, p);
if (mismatch<bestMismatch) {
bestPart = p;
bestMismatch = mismatch;
}
}
return bestPart;
}
public OutlierRecord(EquivRecord r) {
parts = new Part[r.numCircuits()];
Iterator<Circuit> it = r.getCircuits();
// find outlier of 0th Circuit
Outlier outlier = findOutlier((Circuit) it.next());
deviation = outlier.deviation;
parts[0] = outlier.part;
if (deviation==0) return;
// find closest sized Parts from all other Circuits
// parts[0] already initialized
for (int cktNdx=1; it.hasNext(); cktNdx++) {
Circuit c = (Circuit) it.next();
parts[cktNdx] = findClosestSizedPart(c, outlier.part);
}
}
public double deviation() {return deviation;}
public EquivRecord getEquivRecord() {
return parts[0].getParent().getParent();
}
public boolean isOutlier(Part p) {
for (int i=0; i<parts.length; i++) {
if (p==parts[i]) return true;
}
return false;
}
}
/** If Hash code partitioning fails to match all equivalence classes then try to
* partition equivalence classes containing Transistors and Resistors based on
* widths and lengths. This must be done before random matching or else we'll
* get width and length mismatches. */
public class StratSizes extends Strategy {
private static final Integer CODE_OUTLIER = new Integer(1);
private static final Integer CODE_REST = new Integer(2);
private OutlierRecord outlierRecord;
private StratSizes(NccGlobals globals) {super(globals);}
private OutlierRecord findOutlierRecordWithLargestDeviation() {
OutlierRecord furthestOut = null;
Iterator<EquivRecord> frontier = globals.getPartLeafEquivRecs().getNotMatched();
while (frontier.hasNext()) {
EquivRecord r = frontier.next();
if (!r.isBalanced()) continue;
OutlierRecord farOut = new OutlierRecord(r);
if (farOut.deviation()==0) continue;
if (furthestOut==null) {
furthestOut = farOut;
} else if (farOut.deviation()>furthestOut.deviation()) {
furthestOut = farOut;
}
}
return furthestOut;
}
private LeafList doYourJob() {
OutlierRecord r = findOutlierRecordWithLargestDeviation();
if (r==null) return new LeafList();
outlierRecord = r;
return doFor(r.getEquivRecord());
}
@Override
public Integer doFor(NetObject n){
Part p = (Part) n;
return outlierRecord.isOutlier(p) ? CODE_OUTLIER : CODE_REST;
}
//----------------------------- intended interface ------------------------
/** Find the equivalence class with the largest deviation in Part
* sizes and partition that class based on sizes.
* @return the offspring resulting from the partition. Return an empty list
* if no partitioning was possible. */
public static LeafList doYourJob(NccGlobals globals){
StratSizes ss = new StratSizes(globals);
return ss.doYourJob();
}
}