/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: NodeEquivalence.java * * Copyright (c) 2005 Sun Microsystems and Static Free Software * * 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.result.equivalence; import java.io.Serializable; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.hierarchy.HierarchyEnumerator.NodableNameProxy; import com.sun.electric.database.variable.VarContext; import com.sun.electric.tool.Job; /** Object to map from a Nodable in one design to the * "NCC equivalent" Nodable in the * other design. */ class NodeEquivalence implements Serializable { static final long serialVersionUID = 0; private final NodableNameProxy[][] equivNodes; private final int numDesigns, numNodes; private InstancePathToNccContext[] instToNccCtxt; /** Cache the index of the last design that satisified the last * findEquivalent() query? */ private int lastDesignHit; private void pr(String s) {System.out.print(s);} private void prln(String s) {System.out.println(s);} /** Tricky: Because instToNccCtxt takes so much space, build it * only on demand */ private void buildNameTree() { if (instToNccCtxt!=null) return; instToNccCtxt = new InstancePathToNccContext[numDesigns]; for (int i=0; i<numDesigns; i++) { Job.error(equivNodes[i].length!=numNodes, "designs don't have same numbers of nodables?"); instToNccCtxt[i] = new InstancePathToNccContext(equivNodes[i]); } } /** @param equivNodes is a NodableNameProxy[][]. NodableNameProxy[d][n] * gives the nth Nodable of the dth design. NodableNameProxy[a][n] is "NCC * equivalent" to NodableNameProxy[b][n] for all a and b. */ public NodeEquivalence(NodableNameProxy[][] equivNodes) { this.equivNodes = equivNodes; numDesigns = equivNodes.length; numNodes = equivNodes[0].length; } private NodableNameProxy findEquivalent(VarContext vc, Nodable node, int designIndex) { Job.error(designIndex!=0 && designIndex!=1, "designIndex must be 0 or 1"); buildNameTree(); InstancePathToNccContext nameIndex = instToNccCtxt[designIndex]; NccContext nc = nameIndex.findNccContext(vc); if (nc==null) return null; if (nc.getCell()!=node.getParent()) return null; if (!nc.getContext().equals(vc)) return null; for (Iterator<Integer> it=nc.getIndices(); it.hasNext();) { int index = it.next().intValue(); NodableNameProxy prox = equivNodes[designIndex][index]; if (prox.leafName().equals(node.getName())) { int equivDesign = designIndex==0 ? 1 : 0; return equivNodes[equivDesign][index]; } } return null; } private int countUnique() { Set<Nodable> nodes = new HashSet<Nodable>(); for (int i=0; i<2; i++) { for (int j=0; j<numNodes; j++) nodes.add(equivNodes[i][j].getNodable()); } return nodes.size(); } /** Given a Nodable located at point in the design hierarchy specified by a * VarContext, find the "NCC equivalent" Nodable in the other design. * <p> * This code was copied from NetEquivalence. It depends upon 1) the * .equals() equality of instance names along the VarContext, 2) the .equals() * equality of the VarContext (which depends upon the == equality of Nodables * along the VarContext), 3) the .equals equality of the names of the Nodable. * 4) the == equality of the parent Cells of the Nodable * @param vc VarContext specifying a point in the hierarchy. * @param node Nodable located at that point in the hierarchy. * @return the "NCC equivalent" NodableNameProxy or null if no equivalent can * be found. */ public NodableNameProxy findEquivalent(VarContext vc, Nodable node) { NodableNameProxy nnp = findEquivalent(vc, node, lastDesignHit); if (nnp!=null) return nnp; int otherDesign = lastDesignHit==0 ? 1 : 0; nnp = findEquivalent(vc, node, otherDesign); if (nnp!=null) {lastDesignHit=otherDesign; return nnp;} return null; } /** Release cached information when you no longer need the Equivalence * information. */ void clearCache() { instToNccCtxt = null; } /** Regression test. Map from every nodable in design 0 to "NCC * equivalent" nodable in design 1. Map from every nodable in design 1 * to "NCC equivalent" nodable in design 0. * @return the number of errors. */ public int regressionTest() { Job.error(numDesigns!=2, "we must have exactly two designs"); int numErrors = 0; for (int desNdx=0; desNdx<numDesigns; desNdx++) { int otherDesign = desNdx==0 ? 1 : 0; for (int nodeNdx=0; nodeNdx<numNodes; nodeNdx++) { NodableNameProxy from = equivNodes[desNdx][nodeNdx]; VarContext fromVc = from.getContext(); Nodable fromNode = from.getNodable(); NodableNameProxy to = findEquivalent(fromVc, fromNode); if (to!=equivNodes[otherDesign][nodeNdx]) { numErrors++; // Print Diagnostics prln(" From: "+from.toString()); prln(" To: "+(to==null?"null":to.toString())); prln(" Equiv: "+equivNodes[otherDesign][nodeNdx]); } } } pr(" Node equivalence regression "+ (numErrors==0 ? "passed. " : "failed. ")); pr(" Equiv table size="+numNodes+". "); pr(" Num unique Nodables="+countUnique()+". "); if (numErrors!=0) System.out.print(numErrors+" errors."); pr("\n"); return numErrors; } }