/**
   * Transforms a maximally directed pattern (PDAG) represented in graph <code>g</code> into an
   * arbitrary DAG by modifying <code>g</code> itself. Based on the algorithm described in
   * Chickering (2002) "Optimal structure identification with greedy search" Journal of Machine
   * Learning Research. R. Silva, June 2004
   */
  public static void pdagToDag(Graph g) {
    Graph p = new EdgeListGraph(g);
    List<Edge> undirectedEdges = new ArrayList<Edge>();

    for (Edge edge : g.getEdges()) {
      if (edge.getEndpoint1() == Endpoint.TAIL
          && edge.getEndpoint2() == Endpoint.TAIL
          && !undirectedEdges.contains(edge)) {
        undirectedEdges.add(edge);
      }
    }
    g.removeEdges(undirectedEdges);
    List<Node> pNodes = p.getNodes();

    do {
      Node x = null;

      for (Node pNode : pNodes) {
        x = pNode;

        if (p.getChildren(x).size() > 0) {
          continue;
        }

        Set<Node> neighbors = new HashSet<Node>();

        for (Edge edge : p.getEdges()) {
          if (edge.getNode1() == x || edge.getNode2() == x) {
            if (edge.getEndpoint1() == Endpoint.TAIL && edge.getEndpoint2() == Endpoint.TAIL) {
              if (edge.getNode1() == x) {
                neighbors.add(edge.getNode2());
              } else {
                neighbors.add(edge.getNode1());
              }
            }
          }
        }
        if (neighbors.size() > 0) {
          Collection<Node> parents = p.getParents(x);
          Set<Node> all = new HashSet<Node>(neighbors);
          all.addAll(parents);
          if (!GraphUtils.isClique(all, p)) {
            continue;
          }
        }

        for (Node neighbor : neighbors) {
          Node node1 = g.getNode(neighbor.getName());
          Node node2 = g.getNode(x.getName());

          g.addDirectedEdge(node1, node2);
        }
        p.removeNode(x);
        break;
      }
      pNodes.remove(x);
    } while (pNodes.size() > 0);
  }
Example #2
0
  private boolean dConnected(Graph graph, String x, String y, String... z) {
    Node _x = graph.getNode(x);
    Node _y = graph.getNode(y);

    List<Node> _z = new ArrayList<Node>();

    for (String name : z) {
      _z.add(graph.getNode(name));
    }

    return graph.isDConnectedTo(_x, _y, _z);
  }
  public static void arrangeByKnowledgeTiers(Graph graph, Knowledge knowledge) {
    if (knowledge.getNumTiers() == 0) {
      throw new IllegalArgumentException("There are no Tiers to arrange.");
    }

    List<Node> nodes = graph.getNodes();
    List<String> varNames = new ArrayList<String>();
    int ySpace = 500 / knowledge.getNumTiers();
    ySpace = ySpace < 50 ? 50 : ySpace;

    for (Node node1 : nodes) {
      varNames.add(node1.getName());
    }

    List<String> notInTier = knowledge.getVarsNotInTier(varNames);

    int x = 0;
    int y = 50 - ySpace;

    if (notInTier.size() > 0) {
      y += ySpace;

      for (String name : notInTier) {
        x += 90;
        Node node = graph.getNode(name);

        if (node != null) {
          node.setCenterX(x);
          node.setCenterY(y);
        }
      }
    }

    for (int i = 0; i < knowledge.getNumTiers(); i++) {
      List<String> tier = knowledge.getTier(i);
      y += ySpace;
      x = -25;

      for (String name : tier) {
        x += 90;
        Node node = graph.getNode(name);

        if (node != null) {
          node.setCenterX(x);
          node.setCenterY(y);
        }
      }
    }
  }
Example #4
0
  private Graph changeLatentNames(Graph full, Clusters measurements, List<String> latentVarList) {
    Graph g2 = null;

    try {
      g2 = (Graph) new MarshalledObject(full).get();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    for (int i = 0; i < measurements.getNumClusters(); i++) {
      List<String> d = measurements.getCluster(i);
      String latentName = latentVarList.get(i);

      for (Node node : full.getNodes()) {
        if (!(node.getNodeType() == NodeType.LATENT)) {
          continue;
        }

        List<Node> _children = full.getChildren(node);

        _children.removeAll(ReidentifyVariables.getLatents(full));

        List<String> childNames = getNames(_children);

        if (new HashSet<String>(childNames).equals(new HashSet<String>(d))) {
          g2.getNode(node.getName()).setName(latentName);
        }
      }
    }

    return g2;
  }
Example #5
0
  // Trying to trip up the breadth first algorithm.
  public void testDSeparation3() {
    Graph graph = GraphConverter.convert("x-->s1,x-->s2,s1-->s3,s3-->s2,s3<--y");
    assertTrue(
        graph.isDSeparatedFrom(graph.getNode("x"), graph.getNode("y"), new ArrayList<Node>()));

    graph = GraphConverter.convert("1-->2,2<--4,2-->7,2-->3");
    assertTrue(
        graph.isDSeparatedFrom(graph.getNode("4"), graph.getNode("1"), new ArrayList<Node>()));

    graph = GraphConverter.convert("X1-->X5,X1-->X6,X2-->X3,X4-->X6,X5-->X3,X6-->X5,X7-->X3");
    assertTrue(dConnected(graph, "X2", "X4", "X3", "X6"));

    graph = GraphConverter.convert("X1<--X2,X1<--X3,X2-->X3,X3<--X4");
    assertTrue(dConnected(graph, "X1", "X4", "X3"));

    graph = GraphConverter.convert("X2-->X7,X3-->X2,X5-->X1,X5-->X2,X6-->X1,X7-->X6,X2->X4");
    assertTrue(dConnected(graph, "X1", "X3"));

    graph = GraphConverter.convert("1-->3,1-->4,2-->5,4-->5,4-->7,6-->5,7-->3");
    assertTrue(dConnected(graph, "1", "4"));
  }
Example #6
0
  /* Processing assignments of actuals to formals at a call
  site. The first parameter is the call instruction. The second
  is the formal parameter. The last two represent the variable or
  the field being passed.

  For return values, the second parameter is the formal return
  variable in the callee, and the last two parameters are the
  variable/field that the call is assigned to. */
  public void assignParams(Call call, Var p, Var x, Field f, boolean isBasic) {

    if (!isBasic) {
      Method callee = call.getCallee();
      Graph gcallee = PointsToAnalysis.v().getGraph(callee);

      Node nodeL = gcallee.getNode(p, null);
      Node nodeR = this.getNode(x, f);
      if (Options.mergeGraphs.value && this == gcallee) {
        if (p.isReturn()) w.addFirst(new UnifyConstraint(nodeR, nodeL));
        else w.addFirst(new UnifyConstraint(nodeL, nodeR));
      }
      callsites.add(call);
      callees.add(callee);
      gcallee.callers.add(method);
      gcallee.w.add(new CallConstraint(nodeR, nodeL, call));
    }

    if (f != null) setTouched(x);
  }
  /**
   * Transforms a DAG represented in graph <code>graph</code> into a maximally directed pattern
   * (PDAG) by modifying <code>g</code> itself. Based on the algorithm described in Chickering
   * (2002) "Optimal structure identification with greedy search" Journal of Machine Learning
   * Research. It works for both BayesNets and SEMs. R. Silva, June 2004
   */
  public static void dagToPdag(Graph graph) {
    // do topological sort on the nodes
    Graph graphCopy = new EdgeListGraph(graph);
    Node orderedNodes[] = new Node[graphCopy.getNodes().size()];
    int count = 0;
    while (graphCopy.getNodes().size() > 0) {
      Set<Node> exogenousNodes = new HashSet<Node>();

      for (Node next : graphCopy.getNodes()) {
        if (graphCopy.isExogenous(next)) {
          exogenousNodes.add(next);
          orderedNodes[count++] = graph.getNode(next.getName());
        }
      }

      graphCopy.removeNodes(new ArrayList<Node>(exogenousNodes));
    }
    // ordered edges - improvised, inefficient implementation
    count = 0;
    Edge edges[] = new Edge[graph.getNumEdges()];
    boolean edgeOrdered[] = new boolean[graph.getNumEdges()];
    Edge orderedEdges[] = new Edge[graph.getNumEdges()];

    for (Edge edge : graph.getEdges()) {
      edges[count++] = edge;
    }

    for (int i = 0; i < edges.length; i++) {
      edgeOrdered[i] = false;
    }

    while (count > 0) {
      for (Node orderedNode : orderedNodes) {
        for (int k = orderedNodes.length - 1; k >= 0; k--) {
          for (int q = 0; q < edges.length; q++) {
            if (!edgeOrdered[q]
                && edges[q].getNode1() == orderedNodes[k]
                && edges[q].getNode2() == orderedNode) {
              edgeOrdered[q] = true;
              orderedEdges[orderedEdges.length - count] = edges[q];
              count--;
            }
          }
        }
      }
    }

    // label edges
    boolean compelledEdges[] = new boolean[graph.getNumEdges()];
    boolean reversibleEdges[] = new boolean[graph.getNumEdges()];
    for (int i = 0; i < graph.getNumEdges(); i++) {
      compelledEdges[i] = false;
      reversibleEdges[i] = false;
    }
    for (int i = 0; i < graph.getNumEdges(); i++) {
      if (compelledEdges[i] || reversibleEdges[i]) {
        continue;
      }
      Node x = orderedEdges[i].getNode1();
      Node y = orderedEdges[i].getNode2();
      for (int j = 0; j < orderedEdges.length; j++) {
        if (orderedEdges[j].getNode2() == x && compelledEdges[j]) {
          Node w = orderedEdges[j].getNode1();
          if (!graph.isParentOf(w, y)) {
            for (int k = 0; k < orderedEdges.length; k++) {
              if (orderedEdges[k].getNode2() == y) {
                compelledEdges[k] = true;
                break;
              }
            }
          } else {
            for (int k = 0; k < orderedEdges.length; k++) {
              if (orderedEdges[k].getNode1() == w && orderedEdges[k].getNode2() == y) {
                compelledEdges[k] = true;
                break;
              }
            }
          }
        }
        if (compelledEdges[i]) {
          break;
        }
      }
      if (compelledEdges[i]) {
        continue;
      }
      boolean foundZ = false;

      for (Edge orderedEdge : orderedEdges) {
        Node z = orderedEdge.getNode1();
        if (z != x && orderedEdge.getNode2() == y && !graph.isParentOf(z, x)) {
          compelledEdges[i] = true;
          for (int k = i + 1; k < graph.getNumEdges(); k++) {
            if (orderedEdges[k].getNode2() == y && !reversibleEdges[k]) {
              compelledEdges[k] = true;
            }
          }
          foundZ = true;
          break;
        }
      }

      if (!foundZ) {
        reversibleEdges[i] = true;

        for (int j = i + 1; j < orderedEdges.length; j++) {
          if (!compelledEdges[j] && orderedEdges[j].getNode2() == y) {
            reversibleEdges[j] = true;
          }
        }
      }
    }

    // undirect edges that are reversible
    for (int i = 0; i < reversibleEdges.length; i++) {
      if (reversibleEdges[i]) {
        graph.setEndpoint(orderedEdges[i].getNode1(), orderedEdges[i].getNode2(), Endpoint.TAIL);
        graph.setEndpoint(orderedEdges[i].getNode2(), orderedEdges[i].getNode1(), Endpoint.TAIL);
      }
    }
  }
Example #8
0
  private void addRequiredEdges(Graph graph) {
    if (true) return;
    if (knowledgeEmpty()) return;

    for (Iterator<KnowledgeEdge> it = getKnowledge().requiredEdgesIterator(); it.hasNext(); ) {
      KnowledgeEdge next = it.next();

      Node nodeA = graph.getNode(next.getFrom());
      Node nodeB = graph.getNode(next.getTo());

      if (!graph.isAncestorOf(nodeB, nodeA)) {
        graph.removeEdges(nodeA, nodeB);
        graph.addDirectedEdge(nodeA, nodeB);
        TetradLogger.getInstance()
            .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeA, nodeB));
      }
    }
    for (Edge edge : graph.getEdges()) {
      final String A = edge.getNode1().getName();
      final String B = edge.getNode2().getName();

      if (knowledge.isForbidden(A, B)) {
        Node nodeA = edge.getNode1();
        Node nodeB = edge.getNode2();

        if (nodeA != null
            && nodeB != null
            && graph.isAdjacentTo(nodeA, nodeB)
            && !graph.isChildOf(nodeA, nodeB)) {
          if (!graph.isAncestorOf(nodeA, nodeB)) {
            graph.removeEdges(nodeA, nodeB);
            graph.addDirectedEdge(nodeB, nodeA);
            TetradLogger.getInstance()
                .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA));
          }
        }
        if (!graph.isChildOf(nodeA, nodeB)
            && getKnowledge().isForbidden(nodeA.getName(), nodeB.getName())) {
          if (!graph.isAncestorOf(nodeA, nodeB)) {
            graph.removeEdges(nodeA, nodeB);
            graph.addDirectedEdge(nodeB, nodeA);
            TetradLogger.getInstance()
                .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA));
          }
        }
      } else if (knowledge.isForbidden(B, A)) {
        Node nodeA = edge.getNode2();
        Node nodeB = edge.getNode1();

        if (nodeA != null
            && nodeB != null
            && graph.isAdjacentTo(nodeA, nodeB)
            && !graph.isChildOf(nodeA, nodeB)) {
          if (!graph.isAncestorOf(nodeA, nodeB)) {
            graph.removeEdges(nodeA, nodeB);
            graph.addDirectedEdge(nodeB, nodeA);
            TetradLogger.getInstance()
                .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA));
          }
        }
        if (!graph.isChildOf(nodeA, nodeB)
            && getKnowledge().isForbidden(nodeA.getName(), nodeB.getName())) {
          if (!graph.isAncestorOf(nodeA, nodeB)) {
            graph.removeEdges(nodeA, nodeB);
            graph.addDirectedEdge(nodeB, nodeA);
            TetradLogger.getInstance()
                .log("insertedEdges", "Adding edge by knowledge: " + graph.getEdge(nodeB, nodeA));
          }
        }
      }
    }
  }
Example #9
0
  /** Do an actual deletion (Definition 13 from Chickering, 2002). */
  private void delete(Node x, Node y, List<Node> subset, Graph graph, double bump) {

    Edge trueEdge = null;

    if (trueGraph != null) {
      Node _x = trueGraph.getNode(x.getName());
      Node _y = trueGraph.getNode(y.getName());
      trueEdge = trueGraph.getEdge(_x, _y);
    }

    if (log && verbose) {
      Edge oldEdge = graph.getEdge(x, y);

      String label = trueGraph != null && trueEdge != null ? "*" : "";
      TetradLogger.getInstance()
          .log(
              "deletedEdges",
              (graph.getNumEdges() - 1)
                  + ". DELETE "
                  + oldEdge
                  + " "
                  + subset
                  + " ("
                  + bump
                  + ") "
                  + label);
      out.println(
          (graph.getNumEdges() - 1)
              + ". DELETE "
              + oldEdge
              + " "
              + subset
              + " ("
              + bump
              + ") "
              + label);
    } else {
      int numEdges = graph.getNumEdges() - 1;
      if (numEdges % 50 == 0) out.println(numEdges);
    }

    graph.removeEdge(x, y);

    for (Node h : subset) {
      Edge oldEdge = graph.getEdge(y, h);

      graph.removeEdge(y, h);
      graph.addDirectedEdge(y, h);

      if (log) {
        TetradLogger.getInstance()
            .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(y, h));
      }

      if (verbose) {
        out.println("--- Directing " + oldEdge + " to " + graph.getEdge(y, h));
      }

      if (Edges.isUndirectedEdge(graph.getEdge(x, h))) {
        if (!graph.isAdjacentTo(x, h))
          throw new IllegalArgumentException("Not adjacent: " + x + ", " + h);
        oldEdge = graph.getEdge(x, h);

        graph.removeEdge(x, h);
        graph.addDirectedEdge(x, h);

        if (log) {
          TetradLogger.getInstance()
              .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(x, h));
        }

        if (verbose) {
          out.println("--- Directing " + oldEdge + " to " + graph.getEdge(x, h));
        }
      }
    }
  }
Example #10
0
  // serial.
  private void insert(Node x, Node y, List<Node> t, Graph graph, double bump) {
    if (graph.isAdjacentTo(x, y)) {
      return; // The initial graph may already have put this edge in the graph.
      //            throw new IllegalArgumentException(x + " and " + y + " are already adjacent in
      // the graph.");
    }

    Edge trueEdge = null;

    if (trueGraph != null) {
      Node _x = trueGraph.getNode(x.getName());
      Node _y = trueGraph.getNode(y.getName());
      trueEdge = trueGraph.getEdge(_x, _y);
    }

    graph.addDirectedEdge(x, y);

    if (log) {
      String label = trueGraph != null && trueEdge != null ? "*" : "";
      TetradLogger.getInstance()
          .log(
              "insertedEdges",
              graph.getNumEdges()
                  + ". INSERT "
                  + graph.getEdge(x, y)
                  + " "
                  + t
                  + " "
                  + bump
                  + " "
                  + label);
    } else {
      int numEdges = graph.getNumEdges() - 1;
      if (verbose) {
        if (numEdges % 50 == 0) out.println(numEdges);
      }
    }

    if (verbose) {
      String label = trueGraph != null && trueEdge != null ? "*" : "";
      out.println(
          graph.getNumEdges()
              + ". INSERT "
              + graph.getEdge(x, y)
              + " "
              + t
              + " "
              + bump
              + " "
              + label);
    } else {
      int numEdges = graph.getNumEdges() - 1;
      if (verbose) {
        if (numEdges % 50 == 0) out.println(numEdges);
      }
    }

    for (Node _t : t) {
      Edge oldEdge = graph.getEdge(_t, y);

      if (oldEdge == null) throw new IllegalArgumentException("Not adjacent: " + _t + ", " + y);

      graph.removeEdge(_t, y);
      graph.addDirectedEdge(_t, y);

      if (log && verbose) {
        TetradLogger.getInstance()
            .log("directedEdges", "--- Directing " + oldEdge + " to " + graph.getEdge(_t, y));
        out.println("--- Directing " + oldEdge + " to " + graph.getEdge(_t, y));
      }
    }
  }
Example #11
0
  private void createGraph() {
    graph = new Graph();
    String[] columns = Arrays.copyOf(assayTable[0], assayTable[0].length, String[].class);

    int index = 0;

    ProcessNode lastProcess = null;
    NodeWithComments lastMaterialOrData = null;
    NodeWithComments lastSample = null;
    ISAFactorValue lastFactorValue = null;
    ProtocolExecutionNode lastProtocolExecutionNode = null;
    List<ProtocolExecutionNode> protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>();

    for (String column : columns) {

      if (column.matches(Date.REGEXP)) {
        Date date = new Date(index, column);
        if (lastProtocolExecutionNode != null) {
          lastProtocolExecutionNode.addDate(date);
        }

      } else if (column.matches(Performer.REGEXP)) {
        Performer performer = new Performer(index, column);
        if (lastProtocolExecutionNode != null) {
          lastProtocolExecutionNode.addPerformer(performer);
        }

      } else if (column.matches(ProtocolExecutionNode.REGEXP)) {
        ProtocolExecutionNode protocolExecutionNode = new ProtocolExecutionNode(index, column);
        protocolExecutionNodes.add(protocolExecutionNode);
        lastProtocolExecutionNode = protocolExecutionNode;

        if (lastMaterialOrData != null) {
          protocolExecutionNode.setInputNode(lastMaterialOrData);
        }

        graph.addNode(protocolExecutionNode);

      } else if (column.matches(ProcessNode.REGEXP)) {
        ProcessNode processNode = new ProcessNode(index, column);

        graph.addNode(processNode);
        if (lastMaterialOrData != null) {
          // but it could be a DataNode rather than a material node... do I need a new object?
          // processNode.setInputNode(
          //       new MaterialNode(lastMaterialOrData.getIndex(), lastMaterialOrData.getName()));
          processNode.setInputNode(lastMaterialOrData);
        }
        lastProcess = processNode;
        if (lastProcess != null) {
          lastProcess.addProtocolExecutionNodes(protocolExecutionNodes);
          protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>();
        }

      } else if (column.contains(ISADataNode.CONTAINS) && !column.contains("Comment")) {
        NodeWithComments dataNode = new DataNode(index, column);
        graph.addNode(dataNode);
        lastMaterialOrData = dataNode;

        if (lastProcess != null) {
          lastProcess.setOutputNode(dataNode);
          lastProcess = null;
        } else if (lastProtocolExecutionNode != null) {
          lastProtocolExecutionNode.setOutputNode(dataNode);
          lastProtocolExecutionNode = null;
        }

        if (lastMaterialOrData != null
            && lastProcess == null
            && lastProtocolExecutionNode != null) {
          lastProtocolExecutionNode.setOutputNode(dataNode);
          protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>();
        }

      } else if (column.matches(ISAMaterialAttribute.REGEXP)) {

        ISAMaterialAttribute materialAttribute = new MaterialAttribute(index, column);
        if (lastMaterialOrData != null && lastMaterialOrData instanceof MaterialNode) {
          ((MaterialNode) graph.getNode(lastMaterialOrData.getIndex()))
              .addMaterialAttribute(materialAttribute);
        }

      } else if (column.matches(MaterialNode.REGEXP)) {

        NodeWithComments materialNode = null;
        if (column.matches(ISASampleNode.REGEXP)) {
          materialNode = new SampleNode(index, column);
          lastSample = materialNode;
        } else {
          materialNode = new MaterialNode(index, column);
        }
        // if there is a previous material node
        // and no process node, add a dummy process node
        if (lastMaterialOrData != null
            && lastProcess == null
            && lastProtocolExecutionNode != null) {
          lastProtocolExecutionNode.setOutputNode(materialNode);
          protocolExecutionNodes = new ArrayList<ProtocolExecutionNode>();
        }

        graph.addNode(materialNode);
        lastMaterialOrData = materialNode;
        if (lastProcess != null) {
          lastProcess.setOutputNode(materialNode);
          lastProcess = null;
        }

      } else if (column.matches(ISAFactorValue.REGEXP)) {

        ISAFactorValue factorValue = new FactorValue(index, column);
        lastFactorValue = factorValue;
        if (lastSample != null && lastSample instanceof SampleNode) {
          ((SampleNode) graph.getNode(lastSample.getIndex())).addFactorValue(factorValue);
        }

      } else if (column.matches(ISAUnit.REGEXP)) {

        ISAUnit unit = new Unit(index, column);
        if (lastFactorValue != null) {
          lastFactorValue.setUnit(unit);
        }

      } else if (column.matches(ProcessParameter.REGEXP)) {

        ProcessParameter parameter = new ProcessParameter(index, column);

        if (lastProtocolExecutionNode != null) {
          ((ProcessNode) graph.getNode(lastProtocolExecutionNode.getIndex()))
              .addParameter(parameter);
        }

      } else if (column.matches(CommentNode.REGEXP)) {

        CommentNode commentNode = new CommentNode(index, column);

        if (lastProcess != null
            && lastMaterialOrData != null
            && lastProtocolExecutionNode != null) {

          // lastProcess greater index
          if (lastProcess.getIndex() > lastMaterialOrData.getIndex()
              && lastProcess.getIndex() > lastProtocolExecutionNode.getIndex()) {
            lastProcess.addComment(commentNode);
          } else if (lastMaterialOrData.getIndex() > lastProcess.getIndex()
              && lastMaterialOrData.getIndex() > lastProtocolExecutionNode.getIndex()) {
            lastMaterialOrData.addComment(commentNode);
          } else if (lastProtocolExecutionNode.getIndex() > lastProcess.getIndex()
              && lastProtocolExecutionNode.getIndex() > lastMaterialOrData.getIndex()) {
            lastProtocolExecutionNode.addComment(commentNode);
          }

        } else { // one of them is null

          if (lastProcess != null && lastMaterialOrData != null) {

            if (lastProcess.getIndex() > lastMaterialOrData.getIndex()) {
              lastProcess.addComment(commentNode);
            } else {
              lastMaterialOrData.addComment(commentNode);
            }

          } else if (lastProcess != null && lastProtocolExecutionNode != null) {

            if (lastProcess.getIndex() > lastProtocolExecutionNode.getIndex()) {
              lastProcess.addComment(commentNode);
            } else {
              lastProtocolExecutionNode.addComment(commentNode);
            }

          } else if (lastMaterialOrData != null && lastProtocolExecutionNode != null) {

            if (lastMaterialOrData.getIndex() > lastProtocolExecutionNode.getIndex()) {
              lastMaterialOrData.addComment(commentNode);
            } else {
              lastProtocolExecutionNode.addComment(commentNode);
            }

          } else {

            // only one is not null

            if (lastMaterialOrData != null) {
              lastMaterialOrData.addComment(commentNode);
            } else if (lastProcess != null) {
              lastProcess.addComment(commentNode);
            } else if (lastProtocolExecutionNode != null) {
              lastProtocolExecutionNode.addComment(commentNode);
            }
          }
        }
      }
      index++;
    }
  }
  /**
   * run as <CODE>
   * java -cp &lt;classpath&gt; graph.packing.DBBGASPPacker &lt;graphfilename&gt; &lt;paramsfilename&gt; [maxnumBBnodes] [numthreads]
   * </CODE>. <br>
   * args[0]: graph file name must adhere to the format specified in the description of the method
   * <CODE>utils.DataMgr.readGraphFromFile2(String file)</CODE> <br>
   * args[1]: params file name may define parameters in lines of the following form:
   *
   * <ul>
   *   <li>acchost, $string$ optional, the internet address of the DAccumulatorSrv that will be
   *       accumulating incumbents. Default is localhost.
   *   <li>accport, $num$ optional, the port to which the DAccumulatorSrv listens. Default is 7900.
   *   <li>cchost, $string$ optional, the internet address of the DConditionCounterSrv that will be
   *       listening for distributed condition-counter requests. Default is localhost.
   *   <li>ccport, $num$ optional, the port to which the DAccumulatorSrv listens. Default is 7899.
   *   <li>pdahost, $string$ optional, the internet address of the PDAsynchBatchTaskExecutorSrv that
   *       will be listening for distributed tasks execution requests. Default is localhost.
   *   <li>pdaport, $num$ optional, the port to which the asynch distributed executor server
   *       listens. Default is 7981.
   *   <li>tightenboundlevel, $num$ optional, the depth in the B&amp;B tree constructed at which a
   *       stronger computation of the upper bound will be started, default is 0.
   *   <li>cutnodes, $boolean$ optional, if true, then when the BBQueue of nodes is full, any new
   *       nodes created will be discarded instead of processed on the same thread. Default is
   *       false.
   *   <li>localsearch, $boolean$ optional, if true, then when an incumbent solution is found that
   *       cannot be further improved, a local search kicks in to try to improve it using (unless
   *       there is another explicit specification) the (default) N1RXP(FirstImproving) neighborhood
   *       concept that basically attempts to remove a single node from the solution and then see
   *       how many other nodes it can add to the reduced solution. This local search can become
   *       quite expensive and for this reason it is only applied to final incumbent solutions in
   *       the B &amp; B-tree construction process. Default is false.
   *   <li>class,localsearchtype, &lt;fullclassname&gt;[,optionalarguments] optional if present,
   *       will utilize in the local-search procedure the <CODE>AllChromosomeMakerClonableIntf
   *       </CODE> specified in the classname, constructed using the arguments specified (if
   *       present). For example, the line could be:
   *       <PRE>
   * class,localsearchtype,graph.packing.IntSetN2RXPGraphAllMovesMaker,1
   * </PRE>
   *       which would be of use with MWIS problems, for random graphs in the class C(n,p),
   *       producing G_{|V|,p} type random graphs. On the other hand, by default, the <CODE>
   *       IntSetN1RXPFirstImprovingGraphAllMovesMakerMT</CODE> moves maker applies both for 1- and
   *       2-packing problems local-search, which is also better suited when solving MWIS problems
   *       arising from duals of disk graphs (arising from wireless ad-hoc networks etc.) Currently
   *       works only with MWIS (k=1) type problems and is ignored for 2-packing problems.
   *   <li>usemaxsubsets, $boolean$ optional, if false, then each GASP process augmenting candidate
   *       packings will augment these sets one node at a time, leading to the possibility that many
   *       active nodes in the B&amp;B tree will represent the same packing. In such a case, a
   *       "recent-nodes" queue will be used to safe-guard against the possibility of having the
   *       same nodes created and processed within a "short" interval. Default is true.
   *   <li>sortmaxsubsets, $boolean$ optional, if true, then the max subsets generated in method
   *       <CODE>getBestNodeSets2Add()</CODE> will be sorted in descending weight order so that if
   *       children <CODE>BBNode*</CODE> objects are "cut", they will be the "least" heavy-weight.
   *       Default is false.
   *   <li>maxitersinGBNS2A, $num$ optional, if present and also the "usemaxsubsets" key is true,
   *       then the number represents the max number of iterations the <CODE>getBestNodeSets2Add()
   *       </CODE> method of the <CODE>DBBNode1</CODE> class will be allowed to go through. Default
   *       is 100000 (specified in <CODE>DBBTree</CODE> class.)
   *   <li>useGWMIN2criterion, $boolean$ optional, if true, then when computing the best nodes to
   *       consider as a partial solution is being expanded, the "GWMIN2-heuristic" criterion
   *       (described in Sakai et. al. 2003: "A note on greedy algorithms for the MWIS problem",
   *       Discr. Appl. Math., 126:313-322) will be used for nodes selection in 1-packing problems.
   *       Default is false.
   *   <li>maxnodechildren, $num$ optional, specify an upper bound on the number of children any
   *       node is allowed to create. Default is Integer.MAX_VALUE.
   *   <li>class,dbbnodecomparator, &lt;fullclassname&gt; optional, the full class name of a class
   *       implementing the <CODE>graph.packing.DBBNodeComparatorIntf</CODE> that is used to define
   *       the order in which B&amp;B nodes in the tree are picked for processing. Default is <CODE>
   *       graph.packing.DefDBBNodeComparator</CODE>.
   *   <li>ff, $num$ optional, specify the "fudge factor" used in determining what constitutes the
   *       list of "best nodes" in the 1-packing problem (a.k.a. the MWIS problem) where it makes
   *       much more sense to have a "fudge factor" by which to multiply the best cost in order to
   *       determine if a node is "close enough" to the best cost to be included in the
   *       best-candidate-nodes list. Default value is <CODE>DBBNode1._ff</CODE> (currently set to
   *       0.85). The smaller this value, the longer it will take for the search to complete, with
   *       potentially better solutions found.
   *   <li>minknownbound, $num$ optional, a known bound to the problem at hand, which will be used
   *       to fathom B&amp;B nodes having smaller bounds than this number. Currently only applies to
   *       1-packing problems. Default is -infinity.
   *   <li>expandlocalsearchfactor, $num$ optional, if present, then when a solution is found within
   *       the specified factor of the best known solution, a local search kicks in. Default is 1.0
   *       (only when a best solution is found does local search kicks in). Currently only applies
   *       to 1-packing problems.
   * </ul>
   *
   * <br>
   * args[2]: [optional] override max num nodes in params_file to create in B&amp;B procedure
   *
   * <p>This implementation writes the solution in a text file called "sol.out" in the current
   * directory, whose lines contain one number each, the id of each "active" node in the solution
   * (id in the set {1,...graph_num_nodes}).
   *
   * @param args String[]
   */
  public static void main(String[] args) {
    try {
      if (args.length < 2) {
        System.err.println(
            "usage: java -cp <classpath> graph.packing.DBBGASPPacker <graphfilename> <paramsfilename> [maxnumBBnodes]");
        System.exit(-1);
      }
      long start = System.currentTimeMillis();
      Graph g = DataMgr.readGraphFromFile2(args[0]);
      // print out total value weight of the nodes
      {
        double totw = 0.0;
        for (int i = 0; i < g.getNumNodes(); i++) {
          Double w = g.getNode(i).getWeightValue("value");
          totw += w == null ? 1.0 : w.doubleValue();
        }
        System.err.println("Graph total nodes' weight=" + totw);
      }
      HashMap params = DataMgr.readPropsFromFile(args[1]);
      int maxnodes = -1;
      if (args.length > 2) maxnodes = Integer.parseInt(args[2]); // override max num nodes

      Graph[] graphs = null;
      if (g.getNumComponents() > 1) {
        // graphs = g.getGraphComponents();
        System.err.println(
            "Distributed BBGASPPacker does not currently support breaking graphs into disconnected components...");
        System.exit(-1);
      } else { // optimize when there is only one component in the graph
        graphs = new Graph[1];
        graphs[0] = g;
      }
      // now run the B&B algorithm for each sub-graph
      PrintWriter pw = new PrintWriter(new FileWriter("sol.out"));
      for (int j = 0; j < graphs.length; j++) {
        Graph gj = graphs[j];
        System.err.println(
            "Solving for subgraph "
                + (j + 1)
                + " w/ sz="
                + gj.getNumNodes()
                + " (/"
                + graphs.length
                + ")");
        if (gj.getNumNodes() == 3 && gj.getNumArcs() == 2) {
          _totActiveNodes += 2;
          ++_totLeafNodes;
          // figure out which node is the connecting one
          int best_node_id = -1;
          for (int m = 0; m < 3; m++) {
            Node nm = gj.getNode(m);
            if (nm.getNbors().size() == 1) {
              Double nmwD = nm.getWeightValue("value");
              double w = nmwD == null ? 1.0 : nmwD.doubleValue();
              _totActiveNodeWeights += w;
              Integer mI = (Integer) gj.getNodeLabel(m);
              best_node_id = mI == null ? m : mI.intValue(); // null mI -> g connected
              pw.println((best_node_id + 1));
            }
          }
          continue;
        } else if (gj.getNumNodes() <= 2) {
          ++_totActiveNodes;
          ++_totLeafNodes;
          // figure out max. node-weight
          int best_node_id = -1;
          double maxw = Double.NEGATIVE_INFINITY;
          for (int m = 0; m < gj.getNumNodes(); m++) {
            Double nmwD = gj.getNode(m).getWeightValue("value");
            double nmw = nmwD == null ? 1.0 : nmwD.doubleValue();
            if (nmw > maxw) {
              maxw = nmw;
              Integer mI = (Integer) gj.getNodeLabel(m);
              best_node_id = mI == null ? m : mI.intValue(); // null mI -> g connected
            }
          }
          _totActiveNodeWeights += maxw;
          pw.println((best_node_id + 1));
          continue;
        }
        // double bound = Double.MAX_VALUE;
        double bound = 0;
        String pdahost = "localhost";
        if (params.containsKey("pdahost")) pdahost = (String) params.get("pdahost");
        int pdaport = 7981;
        if (params.containsKey("pdaport")) pdaport = ((Integer) params.get("pdaport")).intValue();
        String cchost = "localhost";
        if (params.containsKey("cchost")) cchost = (String) params.get("cchost");
        int ccport = 7899;
        if (params.containsKey("ccport")) ccport = ((Integer) params.get("ccport")).intValue();
        String acchost = "localhost";
        if (params.containsKey("acchost")) acchost = (String) params.get("acchost");
        int accport = 7900;
        if (params.containsKey("accport")) accport = ((Integer) params.get("accport")).intValue();
        // DBBTree.init(g, bound, pdahost, pdaport, cchost, ccport, acchost, accport);
        // DBBTree t = DBBTree.getInstance();
        Boolean localSearchB = (Boolean) params.get("localsearch");
        // if (localSearchB != null) t.setLocalSearch(localSearchB.booleanValue());
        boolean localsearch = false;
        if (localSearchB != null) localsearch = localSearchB.booleanValue();
        AllChromosomeMakerClonableIntf maker =
            (AllChromosomeMakerClonableIntf) params.get("localsearchtype");
        // if (maker!=null) t.setLocalSearchType(maker);
        Double ffD = (Double) params.get("ff");
        /*
        if (ffD!=null) {
        	DBBNode1.setFF(ffD.doubleValue());
        	DBBNode1.disallowFFChanges();
        }
        */
        double ff = 0.85;
        if (ffD != null) ff = ffD.doubleValue();
        Integer tlvlI = (Integer) params.get("tightenboundlevel");
        /*
        if (tlvlI != null && tlvlI.intValue() >= 1) t.setTightenUpperBoundLvl(
        	tlvlI.intValue());
            */
        int tlvl = Integer.MAX_VALUE;
        if (tlvlI != null && tlvlI.intValue() >= 1) tlvl = tlvlI.intValue();
        Boolean usemaxsubsetsB = (Boolean) params.get("usemaxsubsets");
        boolean usemaxsubsets = true;
        if (usemaxsubsetsB != null)
          // t.setUseMaxSubsets(usemaxsubsetsB.booleanValue());
          usemaxsubsets = usemaxsubsetsB.booleanValue();
        int kmax = Integer.MAX_VALUE;
        Integer kmaxI = (Integer) params.get("maxitersinGBNS2A");
        if (kmaxI != null && kmaxI.intValue() > 0)
          // t.setMaxAllowedItersInGBNS2A(kmaxI.intValue());
          kmax = kmaxI.intValue();
        Boolean sortmaxsubsetsB = (Boolean) params.get("sortmaxsubsets");
        boolean sortmaxsubsets = false;
        if (sortmaxsubsetsB != null)
          // t.setSortBestCandsInGBNS2A(sortmaxsubsetsB.booleanValue());
          sortmaxsubsets = sortmaxsubsetsB.booleanValue();
        Double avgpercextranodes2addD = (Double) params.get("avgpercextranodes2add");
        double apen2a = 0.0;
        if (avgpercextranodes2addD != null)
          // t.setAvgPercExtraNodes2Add(avgpercextranodes2addD.doubleValue());
          apen2a = avgpercextranodes2addD.doubleValue();
        Boolean useGWMIN24BN2AB = (Boolean) params.get("useGWMIN2criterion");
        boolean ugwm2 = false;
        if (useGWMIN24BN2AB != null)
          // t.setUseGWMIN24BestNodes2Add(useGWMIN24BN2AB.booleanValue());
          ugwm2 = useGWMIN24BN2AB.booleanValue();
        Double expandlocalsearchfactorD = (Double) params.get("expandlocalsearchfactor");
        double elsf = 1.0;
        if (expandlocalsearchfactorD != null)
          // t.setLocalSearchExpandFactor(expandlocalsearchfactorD.doubleValue());
          elsf = expandlocalsearchfactorD.doubleValue();
        double mkb = Double.NEGATIVE_INFINITY;
        Double minknownboundD = (Double) params.get("minknownbound");
        if (minknownboundD != null) // t.setMinKnownBound(minknownboundD.doubleValue());
        mkb = minknownboundD.doubleValue();
        int maxchildren = Integer.MAX_VALUE;
        Integer maxchildrenI = (Integer) params.get("maxnodechildren");
        if (maxchildrenI != null && maxchildrenI.intValue() > 0)
          // t.setMaxChildrenNodesAllowed(maxchildrenI.intValue());
          maxchildren = maxchildrenI.intValue();
        DBBNodeComparatorIntf bbcomp = (DBBNodeComparatorIntf) params.get("dbbnodecomparator");
        // if (bbcomp!=null) t.setDBBNodeComparator(bbcomp);
        DBBTree.init(
            g,
            bound,
            pdahost,
            pdaport,
            cchost,
            ccport,
            acchost,
            accport,
            localsearch,
            maker,
            ff,
            tlvl,
            usemaxsubsets,
            kmax,
            sortmaxsubsets,
            apen2a,
            ugwm2,
            elsf,
            mkb,
            maxchildren,
            bbcomp);
        DBBTree t = DBBTree.getInstance();
        t.run();
        int orsoln[] = t.getSolution();
        int tan = 0;
        double tanw = 0.0;
        for (int i = 0; i < orsoln.length; i++) {
          if (orsoln[i] == 1) {
            Integer miI = (Integer) gj.getNodeLabel(i);
            int mi = (miI == null) ? i : miI.intValue(); // null miI -> g connected
            // System.out.print( mi + " ");
            pw.println((mi + 1));
            ++tan;
            Double twD = gj.getNode(i).getWeightValue("value");
            tanw += (twD == null ? 1.0 : twD.doubleValue());
          }
        }
        // tanw == t.getBound()
        System.err.println("Total BB-nodes=" + t.getCounter());
        System.err.println("Total leaf BB-nodes=" + t.getTotLeafNodes());
        _totActiveNodes += tan;
        _totActiveNodeWeights += tanw;
        _totLeafNodes += t.getTotLeafNodes();
        System.err.println(
            "Total active nodes so far: "
                + _totActiveNodes
                + " active node weights="
                + _totActiveNodeWeights
                + " total overall trees leaf BB nodes="
                + _totLeafNodes);
        System.err.println(
            "Total #DLS searched performed: "
                + t.getNumDLSPerformed()
                + " Total time spent on DLS: "
                + t.getTimeSpentOnDLS());
      }
      pw.flush();
      pw.close();
      long time = System.currentTimeMillis() - start;
      System.out.println("Best Soln = " + _totActiveNodeWeights);
      System.out.println("\nWall-clock Time (msecs): " + time);
      System.out.println("Done.");
      System.exit(0);
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(-1);
    }
  }