ImmutableNetSchem(Snapshot snapshot, CellId cellId) {
    assert cellId.isIcon() || cellId.isSchematic();
    this.snapshot = snapshot;
    this.cellId = cellId;
    //        System.out.println("begin ImmutableNetSchem " + cellId);
    techPool = snapshot.techPool;
    schem = techPool.getSchematics();
    busPinPortId = schem != null ? schem.busPinNode.getPort(0).getId() : null;
    busArc = schem != null ? schem.bus_arc : null;
    cellTree = snapshot.getCellTree(cellId);
    cellBackup = cellTree.top;
    m = cellBackup.getMemoization();
    cellRevision = cellBackup.cellRevision;
    exports = cellRevision.exports;
    nodes = cellRevision.nodes;
    arcs = cellRevision.arcs;
    numExports = cellRevision.exports.size();
    numNodes = cellRevision.nodes.size();
    numArcs = cellRevision.arcs.size();

    CellId implementationCellId = cellId;
    if (cellId.isIcon()) {
      CellId mainSchemId = snapshot.getMainSchematics(cellId);
      if (mainSchemId != null) {
        getEquivExports(mainSchemId);
        implementationCellId = mainSchemId;
      }
    }
    this.implementationCellId = implementationCellId;

    // init connections
    ni_pi = new int[numNodes];
    int offset = numExports;
    for (int i = 0; i < numNodes; i++) {
      ImmutableNodeInst n = nodes.get(i);
      ni_pi[i] = offset;
      offset += getNumPorts(n.protoId);
    }
    arcsOffset = offset;
    offset += numArcs;

    headConn = new int[offset];
    tailConn = new int[offset];
    drawns = new int[offset];
    for (int i = numExports; i < arcsOffset; i++) {
      headConn[i] = i;
      tailConn[i] = i;
    }
    for (int i = 0; i < numExports; i++) {
      int portOffset = i;
      ImmutableExport export = exports.get(i);
      int orig = getPortInstOffset(export.originalNodeId, export.originalPortId);
      headConn[portOffset] = headConn[orig];
      headConn[orig] = portOffset;
      tailConn[portOffset] = -1;
    }
    for (int arcIndex = 0; arcIndex < numArcs; arcIndex++) {
      ImmutableArcInst a = arcs.get(arcIndex);
      int arcOffset = arcsOffset + arcIndex;
      int head = getPortInstOffset(a.headNodeId, a.headPortId);
      headConn[arcOffset] = headConn[head];
      headConn[head] = arcOffset;
      int tail = getPortInstOffset(a.tailNodeId, a.tailPortId);
      tailConn[arcOffset] = tailConn[tail];
      tailConn[tail] = arcOffset;
    }

    makeDrawns();

    initNetnames();

    portOffsets = new int[numExports + 1];
    drawnNames = new Name[numDrawns];
    drawnWidths = new int[numDrawns];
    drawnOffsets = new int[numDrawns];

    calcDrawnWidths();

    initNodables();

    int mapSize = netNamesOffset + netNames.size();
    int[] netMapN = ImmutableNetLayout.initMap(mapSize);
    localConnections(netMapN);

    int[] netMapP = netMapN.clone();
    int[] netMapA = netMapN.clone();
    internalConnections(netMapN, netMapP, netMapA);

    ImmutableNetLayout.closureMap(netMapN);
    ImmutableNetLayout.closureMap(netMapP);
    ImmutableNetLayout.closureMap(netMapA);

    //        updatePortImplementation();

    updateInterface(netMapN, netMapP, netMapA);
    //        System.out.println("end ImmutableNetSchem " + cellId);
  }
  private void internalConnections(int[] netMapF, int[] netMapP, int[] netMapA) {
    for (int k = 0; k < numNodes; k++) {
      ImmutableNodeInst n = nodes.get(k);
      int nodeOffset = ni_pi[k];
      if (n.protoId instanceof PrimitiveNodeId) {
        PrimitiveNode.Function fun = getFunction(n);
        if (fun == PrimitiveNode.Function.RESIST) {
          ImmutableNetLayout.connectMap(
              netMapP, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]);
          ImmutableNetLayout.connectMap(
              netMapA, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]);
        } else if (fun.isComplexResistor()) {
          ImmutableNetLayout.connectMap(
              netMapA, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]);
        }
        continue;
      }
      IconInst iconInst = iconInsts[k];
      if (iconInst != null) {
        continue;
      }
      CellId subCellId = (CellId) n.protoId;
      assert !subCellId.isIcon() && !subCellId.isSchematic();
      EquivPorts eq = snapshot.getCellTree(subCellId).getEquivPorts();
      int[] eqN = eq.getEquivPortsN();
      int[] eqP = eq.getEquivPortsP();
      int[] eqA = eq.getEquivPortsA();
      int numPorts = eq.getNumExports();
      assert eqN.length == numPorts && eqP.length == numPorts && eqA.length == numPorts;
      for (int i = 0; i < numPorts; i++) {
        int di = drawns[nodeOffset + i];
        if (di < 0) {
          continue;
        }
        int jN = eqN[i];
        if (i != jN) {
          int dj = drawns[nodeOffset + jN];
          if (dj >= 0) {
            ImmutableNetLayout.connectMap(netMapF, drawnOffsets[di], drawnOffsets[dj]);
          }
        }
        int jP = eqP[i];
        if (i != jP) {
          int dj = drawns[nodeOffset + jP];
          if (dj >= 0) {
            ImmutableNetLayout.connectMap(netMapP, drawnOffsets[di], drawnOffsets[dj]);
          }
        }
        int jA = eqA[i];
        if (i != jA) {
          int dj = drawns[nodeOffset + jA];
          if (dj >= 0) {
            ImmutableNetLayout.connectMap(netMapA, drawnOffsets[di], drawnOffsets[dj]);
          }
        }
      }
    }
    for (IconInst iconInst : iconInsts) {
      if (iconInst == null || iconInst.iconOfParent) {
        continue;
      }
      for (int k = 0; k < iconInst.nodeInst.name.busWidth(); k++) {
        EquivalentSchematicExports eq = iconInst.eq.implementation;
        assert eq.implementation == eq;
        int[] eqN = eq.getEquivPortsN();
        int[] eqP = eq.getEquivPortsP();
        int[] eqA = eq.getEquivPortsA();
        int nodableOffset = iconInst.netMapOffset + k * iconInst.numExtendedExports;
        for (int i = 0; i < eqN.length; i++) {
          int io = nodableOffset + i;

          int jF = eqN[i];
          if (i != jF) {
            ImmutableNetLayout.connectMap(netMapF, io, nodableOffset + jF);
          }

          int jP = eqP[i];
          if (i != jP) {
            ImmutableNetLayout.connectMap(netMapP, io, nodableOffset + jP);
          }

          int jA = eqA[i];
          if (i != jA) {
            ImmutableNetLayout.connectMap(netMapA, io, nodableOffset + jA);
          }
        }
      }
    }
  }