/** Checks if a PTA constructed is consistent with provided sequences. */
 private void checkPTAConsistency(
     PTASequenceEngine engine, Set<List<Label>> sequences, boolean accept) {
   SequenceSet initSeq = engine.new SequenceSet();
   initSeq.setIdentity();
   int leafNumber = engine.getDebugDataMapDepth(null).size();
   // Now we check the consistency
   for (List<Label> seq : sequences) {
     SequenceSet endOfSeq =
         initSeq.crossWithSequence(seq); // this is aimed to follow a path in a PTA
     // to a state which is not necessarily a tail-state (hence no use calling
     // getDebugDataMapDepth(null),
     // but can inadvertently add a new sequence, hence we have to check that it has to happened at
     // the end.
     Map<String, String> map = engine.getDebugDataMapDepth(endOfSeq);
     assert map.size() == 1 : "expected size of 1, got " + map.size();
     String attrs = map.values().iterator().next();
     // For reject-sequences,
     // If the end of the sequence is not a leaf, it should be considered an accept-sequence, hence
     // throw.
     // If the end of the sequence is a leaf but should be returned, this is also an
     // accept-sequence (see the sequence engine construction above) throw.
     // The only remaining case is that the end is a leaf and should not be returned - this is ok.
     if (!accept && !attrs.equals(DebugDataValues.booleanToString(true, false)))
       throw new IllegalArgumentException(
           "reject-sequence " + seq + " is present in PTA with a positive ending");
     // For accept-sequences, the only erroneous case is when a leaf is not returned.
     // (we assume that non-leaf is always returned.)
     if (accept && attrs.equals(DebugDataValues.booleanToString(true, false)))
       throw new IllegalArgumentException(
           "reject-sequence " + seq + " is present in PTA with a negative ending");
   }
   Assert.assertEquals(leafNumber, engine.getDebugDataMapDepth(null).size());
 }
  public static PTASequenceEngine buildPTA(
      Set<List<Label>> plusStrings, Set<List<Label>> minusStrings) {
    final Boolean accept = new Boolean(true), reject = new Boolean(false);
    boolean theOnlyStateReject = false;
    for (List<Label> seq : minusStrings)
      if (seq.isEmpty()) {
        theOnlyStateReject = true;
        break;
      }
    final Boolean rejectAllStates = new Boolean(theOnlyStateReject);
    final AtomicBoolean statesAccept = new AtomicBoolean(true);
    PTASequenceEngine allSequences = new PTASequenceEngine();

    // Here we are building a PTA which consists of accept states for plusStrings and reject-states
    // for minusStrings. This way if a plus string is a prefix of a plusString, the prefix will
    // be labelled with Boolean(true) states and the suffix - with Boolean(false) states.
    // Note that the suffix may contain many states.
    allSequences.init(
        new PTASequenceSetAutomaton() {
          @Override
          public Object getTheOnlyState() {
            return statesAccept.get() ? accept : reject;
          }

          @Override
          public boolean shouldBeReturned(Object elem) {
            return elem != null && ((Boolean) elem).booleanValue();
          }

          @Override
          public boolean isAccept(@SuppressWarnings("unused") Object elem) {
            return !rejectAllStates.booleanValue();
          }
        });
    SequenceSet initSeq = allSequences.new SequenceSet();
    initSeq.setIdentity();
    initSeq.cross(plusStrings);
    statesAccept.getAndSet(false);
    initSeq.cross(minusStrings);

    return allSequences;
  }
  /**
   * Builds a PTA from the supplied arguments using two different methods. If any of them throws,
   * checks that another one throws too and then rethrows the exception.
   *
   * @param arrayPlusStrings allowed sequences
   * @param arrayMinusStrings sequences ending at a reject state
   * @param expectedPTA a textual representation of a PTA which should be built.
   * @param expectMaxAutomataToBeTheSameAsPTA whether we expect augmentation of a maximal automaton
   *     to yield the same result as that of a normal PTA.
   */
  private void checkPTAconstruction(
      String[][] arrayPlusStrings,
      String[][] arrayMinusStrings,
      String expectedPTA,
      boolean expectMaxAutomataToBeTheSameAsPTA) {
    Configuration conf = mainConfiguration.copy();
    Set<List<Label>> plusStrings = buildSet(arrayPlusStrings, conf, converter),
        minusStrings = buildSet(arrayMinusStrings, conf, converter);
    LearnerGraph actualA = null, actualC = null, actualD = null, actualE = null, actualF = null;
    IllegalArgumentException eA = null, eC = null, eD = null, eE = null, eF = null;
    try {
      actualA =
          new LearnerGraph(
              Test_Orig_RPNIBlueFringeLearner.createAugmentedPTA(plusStrings, minusStrings), conf);
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eA = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.init(plusStrings, minusStrings);
      actualC = l.getTentativeAutomaton();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eC = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      PTASequenceEngine engine = buildPTA(plusStrings, minusStrings);
      checkPTAConsistency(engine, plusStrings, true);
      if (engine.numberOfLeafNodes() > 0) checkPTAConsistency(engine, minusStrings, false);
      l.init(engine, 0, 0);
      actualD = l.getTentativeAutomaton();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eD = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.init(buildPTA(plusStrings, buildSet(new String[][] {}, config, converter)), 0, 0);
      for (List<Label> seq : minusStrings) {
        Set<List<Label>> negativeSeq = new HashSet<List<Label>>();
        negativeSeq.add(seq);
        l.getTentativeAutomaton()
            .paths
            .augmentPTA(buildPTA(buildSet(new String[][] {}, config, converter), negativeSeq));
      }
      actualE = l.getTentativeAutomaton();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eE = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.getTentativeAutomaton().initPTA();
      l.getTentativeAutomaton().paths.augmentPTA(minusStrings, false, true);
      l.getTentativeAutomaton().paths.augmentPTA(plusStrings, true, true);
      actualF = l.getTentativeAutomaton();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eF = e;
    }

    if (eA != null) {
      Assert.assertNotNull(eC);
      Assert.assertNotNull(eD);
      Assert.assertNotNull(eE);
      if (expectMaxAutomataToBeTheSameAsPTA) Assert.assertNotNull(eF);
      throw eA;
    }

    Assert.assertNull(eA);
    Assert.assertNull(eC);
    Assert.assertNull(eD);
    Assert.assertNull(eE);
    if (expectMaxAutomataToBeTheSameAsPTA) Assert.assertNull(eF);

    Configuration config = mainConfiguration.copy();
    config.setAllowedToCloneNonCmpVertex(true);
    checkM(expectedPTA, actualA, config, converter);
    checkM(expectedPTA, actualC, config, converter);
    checkDepthLabelling(actualC);
    // Visualiser.updateFrame(actualE,FsmParser.buildGraph(expectedPTA,"expected
    // graph"));Visualiser.waitForKey();
    checkM(expectedPTA, actualD, config, converter);
    checkDepthLabelling(actualD);
    checkM(expectedPTA, actualE, config, converter);
    checkDepthLabelling(actualE);

    if (expectMaxAutomataToBeTheSameAsPTA) checkM(expectedPTA, actualF, config, converter);
    checkDepthLabelling(actualF);
  }
  private void checkEmptyPTA(
      String[][] arrayPlusStrings,
      String[][] arrayMinusStrings,
      boolean expectMaxAutomataToBeTheSameAsPTA) {
    Configuration conf = mainConfiguration.copy();
    Set<List<Label>> plusStrings = buildSet(arrayPlusStrings, conf, converter),
        minusStrings = buildSet(arrayMinusStrings, conf, converter);
    DirectedSparseGraph actualA = null,
        actualC = null,
        actualD = null,
        actualE = null,
        actualF = null;
    IllegalArgumentException eA = null, eC = null, eD = null, eE = null, eF = null;
    try {
      actualA = Test_Orig_RPNIBlueFringeLearner.createAugmentedPTA(plusStrings, minusStrings);
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eA = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.init(plusStrings, minusStrings);
      actualC = l.getTentativeAutomaton().pathroutines.getGraph();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eC = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      PTASequenceEngine engine = buildPTA(plusStrings, minusStrings);
      checkPTAConsistency(engine, plusStrings, true);
      if (engine.numberOfLeafNodes() > 0) checkPTAConsistency(engine, minusStrings, false);
      l.init(engine, 0, 0);
      actualD = l.getTentativeAutomaton().pathroutines.getGraph();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eD = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.init(buildPTA(plusStrings, buildSet(new String[][] {}, config, converter)), 0, 0);
      for (List<Label> seq : minusStrings) {
        Set<List<Label>> negativeSeq = new HashSet<List<Label>>();
        negativeSeq.add(seq);
        l.getTentativeAutomaton()
            .paths
            .augmentPTA(buildPTA(buildSet(new String[][] {}, config, converter), negativeSeq));
      }
      actualE = l.getTentativeAutomaton().pathroutines.getGraph();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eE = e;
    }

    try {
      Configuration config = mainConfiguration.copy();
      RPNIUniversalLearner l =
          new RPNIUniversalLearner(
              null, new LearnerEvaluationConfiguration(null, null, config, null, null));
      config.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
      l.getTentativeAutomaton().initPTA();
      l.getTentativeAutomaton().paths.augmentPTA(minusStrings, false, true);
      l.getTentativeAutomaton().paths.augmentPTA(plusStrings, true, true);
      actualF = l.getTentativeAutomaton().pathroutines.getGraph();
    } catch (IllegalArgumentException e) {
      // ignore this - it might be expected.
      eF = e;
    }

    if (eA != null) { // an exception has been thrown, hence verify that all way of PTA construction
      // have thrown too.
      Assert.assertNotNull(eC);
      Assert.assertNotNull(eD);
      Assert.assertNotNull(eE);
      if (expectMaxAutomataToBeTheSameAsPTA) Assert.assertNotNull(eF);
      throw eA;
    }

    Assert.assertNull(eA);
    Assert.assertNull(eC);
    Assert.assertNull(eD);
    Assert.assertNull(eE);
    if (expectMaxAutomataToBeTheSameAsPTA) Assert.assertNull(eF);

    Assert.assertEquals(1, actualA.getVertices().size());
    Assert.assertEquals(
        true,
        DeterministicDirectedSparseGraph.isAccept(
            ((Vertex) actualA.getVertices().iterator().next())));
    Assert.assertEquals(0, actualA.getEdges().size());

    Assert.assertEquals(1, actualC.getVertices().size());
    Assert.assertEquals(
        true,
        DeterministicDirectedSparseGraph.isAccept(
            ((Vertex) actualC.getVertices().iterator().next())));
    Assert.assertEquals(0, ((CmpVertex) (actualC.getVertices().iterator().next())).getDepth());
    Assert.assertEquals(0, actualC.getEdges().size());

    Assert.assertEquals(1, actualD.getVertices().size());
    Assert.assertEquals(
        true,
        DeterministicDirectedSparseGraph.isAccept(
            ((Vertex) actualD.getVertices().iterator().next())));
    Assert.assertEquals(0, ((CmpVertex) (actualD.getVertices().iterator().next())).getDepth());
    Assert.assertEquals(0, actualD.getEdges().size());

    Assert.assertEquals(1, actualE.getVertices().size());
    Assert.assertEquals(
        true,
        DeterministicDirectedSparseGraph.isAccept(
            ((Vertex) actualE.getVertices().iterator().next())));
    Assert.assertEquals(0, ((CmpVertex) (actualE.getVertices().iterator().next())).getDepth());
    Assert.assertEquals(0, actualE.getEdges().size());

    if (expectMaxAutomataToBeTheSameAsPTA) {
      Assert.assertEquals(1, actualF.getVertices().size());
      Assert.assertEquals(
          true,
          DeterministicDirectedSparseGraph.isAccept(
              ((Vertex) actualF.getVertices().iterator().next())));
      Assert.assertEquals(0, ((CmpVertex) (actualF.getVertices().iterator().next())).getDepth());
      Assert.assertEquals(0, actualF.getEdges().size());
    }
  }