public void ruleR3(Graph graph){
  List<Node> nodes=graph.getNodes();
  for (  Node B : nodes) {
    List<Node> intoBArrows=graph.getNodesInTo(B,Endpoint.ARROW);
    List<Node> intoBCircles=graph.getNodesInTo(B,Endpoint.CIRCLE);
    for (    Node D : intoBCircles) {
      if (intoBArrows.size() < 2) {
        continue;
      }
      ChoiceGenerator gen=new ChoiceGenerator(intoBArrows.size(),2);
      int[] choice;
      while ((choice=gen.next()) != null) {
        Node A=intoBArrows.get(choice[0]);
        Node C=intoBArrows.get(choice[1]);
        if (graph.isAdjacentTo(A,C)) {
          continue;
        }
        if (!graph.isAdjacentTo(A,D) || !graph.isAdjacentTo(C,D)) {
          continue;
        }
        if (!sepsets.isNoncollider(A,D,C)) {
          continue;
        }
        if (graph.getEndpoint(A,D) != Endpoint.CIRCLE) {
          continue;
        }
        if (graph.getEndpoint(C,D) != Endpoint.CIRCLE) {
          continue;
        }
        if (!isArrowpointAllowed(D,B,graph)) {
          continue;
        }
        graph.setEndpoint(D,B,Endpoint.ARROW);
        if (verbose) {
          logger.log("impliedOrientations",SearchLogUtils.edgeOrientedMsg("Double triangle",graph.getEdge(D,B)));
          out.println(SearchLogUtils.edgeOrientedMsg("Double triangle",graph.getEdge(D,B)));
        }
        changeFlag=true;
      }
    }
  }
}

public void ruleR3 ( Graph graph ) { List < Node > nodes = graph . getNodes ( ) ; for ( Node B : nodes ) { List < Node > intoBArrows = graph . getNodesInTo ( B , Endpoint . ARROW ) ; List < Node > intoBCircles = graph . getNodesInTo ( B , Endpoint . CIRCLE ) ; for ( Node D : intoBCircles ) { if ( intoBArrows . size ( ) < 2 ) { continue ; } ChoiceGenerator gen = new ChoiceGenerator ( intoBArrows . size ( ) , 2 ) ; int [ ] choice ; while ( ( choice = gen . next ( ) ) != null ) { Node A = intoBArrows . get ( choice [ 0 ] ) ; Node C = intoBArrows . get ( choice [ 1 ] ) ; if ( graph . isAdjacentTo ( A , C ) ) { continue ; } if ( ! graph . isAdjacentTo ( A , D ) || ! graph . isAdjacentTo ( C , D ) ) { continue ; } if ( ! sepsets . isNoncollider ( A , D , C ) ) { continue ; } if ( graph . getEndpoint ( A , D ) != Endpoint . CIRCLE ) { continue ; } if ( graph . getEndpoint ( C , D ) != Endpoint . CIRCLE ) { continue ; } if ( ! isArrowpointAllowed ( D , B , graph ) ) { continue ; } graph . setEndpoint ( D , B , Endpoint . ARROW ) ; if ( verbose ) { logger . log ( "impliedOrientations" , SearchLogUtils . edgeOrientedMsg ( "Double triangle" , graph . getEdge ( D , B ) ) ) ; out . println ( SearchLogUtils . edgeOrientedMsg ( "Double triangle" , graph . getEdge ( D , B ) ) ) ; } changeFlag = true ; } } } }
implements the double - triangle orientation rule , which states that if d * - ob , a * - > b < - * c and a * - odo - * c , then d * - > b . < p > this is zhang ' s rule r3 .
