Package statechum.analysis.learning.spin

Examples of statechum.analysis.learning.spin.SpinUtil


  @Override
  public LearnerGraph learnMachine()
  {
    final Configuration shallowCopy = getTentativeAutomaton().config.copy();shallowCopy.setLearnerCloneGraph(false);
    ptaHardFacts = new LearnerGraph(shallowCopy);// this is now cloned to eliminate counter-examples added to ptaSoftFacts by Spin
    SpinUtil spin = null;
    LearnerGraph.copyGraphs(getTentativeAutomaton(), ptaHardFacts);
    LearnerGraph ptaSoftFacts = getTentativeAutomaton();
    setChanged();getTentativeAutomaton().setName(getGraphName()+"_init");
    final List<List<Label>> extraTracesPlus = new LinkedList<List<Label>>(), extraTracesMinus = new LinkedList<List<Label>>();

    if (config.isUseConstraints())
    {
      LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
      StringBuffer counterExampleHolder = new StringBuffer();
      if (ifthenAutomata == null)
        ifthenAutomata = Transform.buildIfThenAutomata(ifthenAutomataAsText, alphabetUsedForIfThen, ptaHardFacts, config, topLevelListener.getLabelConverter()).toArray(new LearnerGraph[0]);

      if (!topLevelListener.AddConstraints(getTentativeAutomaton(),updatedTentativeAutomaton,counterExampleHolder))
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, counterExampleHolder.toString()));
      setTentativeAutomaton(updatedTentativeAutomaton);
    }
    if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){
      spin = new SpinUtil(config,getLabelConverter());
      SpinResult sr = spin.check(ptaHardFacts, ifthenAutomataAsText);
      if(!sr.isPass())
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, sr.getCounters()));
    }

    Stack<PairScore> possibleMerges = topLevelListener.ChooseStatePairs(getTentativeAutomaton());
    int iterations = 0, currentNonAmber = ptaHardFacts.getStateNumber()-ptaHardFacts.getAmberStateNumber();
    JUConstants colourToAugmentWith = getTentativeAutomaton().config.getUseAmber()? JUConstants.AMBER:null;
    updateGraph(getTentativeAutomaton(),ptaHardFacts);
    while (!possibleMerges.isEmpty())
    {
      iterations++;
      PairScore pair = possibleMerges.pop();
      final LearnerGraph temp = topLevelListener.MergeAndDeterminize(getTentativeAutomaton(), pair);
      Collection<List<Label>> questions = new LinkedList<List<Label>>();
      long score = pair.getScore();
      RestartLearningEnum restartLearning = RestartLearningEnum.restartNONE;// whether we need to rebuild a PTA and restart learning.

      if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){

        Collection<List<Label>> counterExamples = spin.check(temp, getTentativeAutomaton(), ifthenAutomataAsText).getCounters();
        Iterator<List<Label>> counterExampleIt = counterExamples.iterator();
        while(counterExampleIt.hasNext())
        {
          List<Label> counterExample = counterExampleIt.next();
          topLevelListener.AugmentPTA(ptaSoftFacts, RestartLearningEnum.restartSOFT, counterExample, false,colourToAugmentWith);
          System.out.println("<temp> "+counterExample);
         
        }
        if(counterExamples.size()>0)
          restartLearning = RestartLearningEnum.restartSOFT;
      }

      if (config.isUseConstraints())
      {
        LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
        StringBuffer counterExampleHolder = new StringBuffer();
        if (!topLevelListener.AddConstraints(temp,updatedTentativeAutomaton,counterExampleHolder))
        {
          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
          System.out.println("<info> pair "+pair+" contradicts constraints, hence recorded as incompatible");
        }
        // since we still need the outcome of merging to ask questions,
        // we delay actually performing augmentation until the time we are
        // finished with questions.
      }

      Iterator<List<Label>> questionIt = null;

      if (restartLearning == RestartLearningEnum.restartNONE)
      {
        Map<CmpVertex,JUConstants.PAIRCOMPATIBILITY> compatibilityMap = ptaHardFacts.pairCompatibility.compatibility.get(pair.getQ());
        if (pair.getScore() > config.getScoreForAutomergeUponRestart() && compatibilityMap != null && compatibilityMap.get(pair.getR()) == JUConstants.PAIRCOMPATIBILITY.MERGED)
          System.out.println("<automerge of previously merged pair> "+pair);
        else
        {
          // ask questions if needed
          if (shouldAskQuestions(score))
          {
            temp.setName(getGraphName()+"_"+iterations);
            //LearnerGraph updatedGraphActual = ComputeQuestions.constructGraphWithQuestions(pair, tentativeAutomaton, temp);
            //updatedGraphActual.setName(getGraphName(config)+"questions "+iterations);setChanged();updateGraph(updatedGraphActual,ptaHardFacts);
           
            questions = topLevelListener.ComputeQuestions(pair, getTentativeAutomaton(), temp);// all answers are considered "hard", hence we have to ask questions based on hard facts in order to avoid prefixes which are not valid in hard facts
            questionIt = questions.iterator();
            if (questionIt.hasNext())
            {
              pair.firstElem.setHighlight(true);
              pair.secondElem.setHighlight(true);
              updateGraph(getTentativeAutomaton(),ptaHardFacts);
              pair.firstElem.setHighlight(false);
              pair.secondElem.setHighlight(false);
            }
          }
        }
      }

      while (restartLearning == RestartLearningEnum.restartNONE && questionIt != null && questionIt.hasNext())
      {
        List<Label> question = questionIt.next();
       
        boolean accepted = pair.getQ().isAccept();
        Pair<Integer,String> answer = null;
        if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty())
          answer = new Pair<Integer,String>(spin.check(question, ifthenAutomataAsText),null);
       
        CmpVertex tempVertex = temp.getVertex(question);
        boolean answerFromSpin = false;
        if(answer != null && answer.firstElem >= 0)
          answerFromSpin = true;
        else
        {
          if (GlobalConfiguration.getConfiguration().isAssertEnabled())
            if (ptaHardFacts.paths.tracePathPrefixClosed(question) == AbstractOracle.USER_ACCEPTED) {
              throw new IllegalArgumentException("question "+ question+ " has already been answered");
            }
          List<Boolean> acceptedElements = PathRoutines.mapPathToConfirmedElements(ptaHardFacts,question,ifthenAutomata);

          answer = topLevelListener.CheckWithEndUser(getTentativeAutomaton(), question,
              tempVertex.isAccept()?AbstractOracle.USER_ACCEPTED:question.size() - 1,
                  acceptedElements, pair,
              new Object[] { "LTL","IFTHEN","IGNORE QUESTION","MARK AS INCOMPATIBLE","Add trace"});
        }
        if (answer.firstElem == AbstractOracle.USER_CANCELLED)
        {
          System.out.println("CANCELLED");
          return null;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_IGNORED)
        {// do nothing
          restartLearning = RestartLearningEnum.restartNONE;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_INCOMPATIBLE)
        {
          /* When autoanswers says that a particular pair is incompatible, <em>StoredAnswers</em> the answer refers to the current
           * question, but we have to return a pair which is incompatible. Although strange, it is not really surprising - the whole
           * AutoAnswers framework aims to automate debugging hence we are expected to go through the same sequence of questions
           * over and over again - it is enough to validate that we do not deviate and hence all that is necessary is to check that
           * the current pair to be merged is the same as the one recorded as incompatible when an answer was recorded.
           */

          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_NEWTRACE)
        {
          String traceDescr = answer.secondElem;
          boolean obtainedViaAuto = answer.secondElem != null;
          if (traceDescr == null) traceDescr = JOptionPane.showInputDialog("New trace :");
          if(traceDescr != null && traceDescr.length() != 0)
          {
            final JUConstants colour = colourToAugmentWith;
            final AtomicBoolean whetherToRestart = new AtomicBoolean(false);
            QSMTool.parseSequenceOfTraces(traceDescr, config, new TraceAdder() {

              @Override
              public void addTrace(List<Label> trace,  boolean positive) {
                if (positive) extraTracesPlus.add(trace);else extraTracesMinus.add(trace);
                CmpVertex tailVertex = temp.getVertex(trace);
                if (tailVertex != null && tailVertex.isAccept() != positive)
                  whetherToRestart.set(true);
              }
             
            }, getLabelConverter());
         
            if (!obtainedViaAuto) System.out.println(RPNILearner.QUESTION_USER+" "+question.toString()+" "+RPNILearner.QUESTION_NEWTRACE+" "+traceDescr);
            // At this point, we attempt to augment the current automaton with the supplied traces,
            // which may be successful or not (if we did some erroneous mergers earlier), in which case we restart.

                  for(List<Label> positive:extraTracesPlus)
                    AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,positive, true,colour);
            for(List<Label> negative:extraTracesMinus)
              AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,negative, false,colour);
           
            if (whetherToRestart.get())
              restartLearning = RestartLearningEnum.restartHARD;// we've seen at least one trace which contradicts the new tentative PTA.
            else
              restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;// the set of questions will be rebuilt because we possibly modified the "nonexistent" PTA containing questions.
          }
        }
        else
        if (answer.firstElem == AbstractOracle.USER_ACCEPTED)
        {
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,question, true,colourToAugmentWith);
         
          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,question, true,colourToAugmentWith);

          if (!tempVertex.isAccept())
          {// contradiction with the result of merging
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
        if (answer.firstElem >= 0)
        {// The sequence has been rejected by a user
          assert answer.firstElem < question.size();
          LinkedList<Label> subAnswer = new LinkedList<Label>();
          subAnswer.addAll(question.subList(0, answer.firstElem + 1));
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts, RestartLearningEnum.restartHARD,subAnswer, false,colourToAugmentWith);

          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,subAnswer, false,colourToAugmentWith);
          // important: since vertex IDs is
          // only unique for each instance of ComputeStateScores, only
          // one instance should ever receive calls to augmentPTA

          if ((answer.firstElem < question.size() - 1) || tempVertex.isAccept())
          {// contradiction with the result of merging
            assert accepted == true;
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
          if(answer.firstElem == AbstractOracle.USER_LTL || answer.firstElem == AbstractOracle.USER_IFTHEN)
          {
            String answerType = null;
            if (answer.firstElem == AbstractOracle.USER_LTL)
              answerType = QSMTool.cmdLTL;
            else
              if (answer.firstElem == AbstractOracle.USER_IFTHEN)
                answerType = QSMTool.cmdIFTHENAUTOMATON;
              else
                throw new IllegalArgumentException("unexpected user choice kind "+answer.firstElem);

            restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;
            String addedConstraint = answer.secondElem;
            boolean obtainedLTLViaAuto = addedConstraint != null;
            if (addedConstraint == null) addedConstraint = JOptionPane.showInputDialog("New "+answerType+" formula:");
            if(addedConstraint != null && addedConstraint.length() != 0)
            {
              if (!obtainedLTLViaAuto) System.out.println(QUESTION_USER+" "+question.toString()+ " <"+answerType+"> "+addedConstraint);
              Set<String> tmpLtl = new HashSet<String>();tmpLtl.addAll(ifthenAutomataAsText);tmpLtl.add(answerType+" "+addedConstraint);
              if(!config.isUseConstraints())
              {
                Collection<List<Label>> counters = spin.check(ptaHardFacts, tmpLtl).getCounters();
                if (counters.size()>0)
                {
                  String errorMessage = getHardFactsContradictionErrorMessage(tmpLtl, counters);
                  if (obtainedLTLViaAuto) // cannot recover from autosetting, otherwise warn a user
                    throw new IllegalArgumentException(errorMessage);
View Full Code Here


  @Override
  public LearnerGraph learnMachine()
  {
    final Configuration shallowCopy = getTentativeAutomaton().config.copy();shallowCopy.setLearnerCloneGraph(false);
    ptaHardFacts = new LearnerGraph(shallowCopy);// this is now cloned to eliminate counter-examples added to ptaSoftFacts by Spin
    SpinUtil spin = null;
    LearnerGraph.copyGraphs(getTentativeAutomaton(), ptaHardFacts);
    LearnerGraph ptaSoftFacts = getTentativeAutomaton();
    setChanged();getTentativeAutomaton().setName(getGraphName()+"_init");
    final List<List<Label>> extraTracesPlus = new LinkedList<List<Label>>(), extraTracesMinus = new LinkedList<List<Label>>();

    if (config.isUseConstraints())
    {
      LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
      StringBuffer counterExampleHolder = new StringBuffer();
      if (ifthenAutomata == null)
        ifthenAutomata = Transform.buildIfThenAutomata(ifthenAutomataAsText, ptaHardFacts, config, topLevelListener.getLabelConverter()).toArray(new LearnerGraph[0]);

      if (!topLevelListener.AddConstraints(getTentativeAutomaton(),updatedTentativeAutomaton,counterExampleHolder))
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, counterExampleHolder.toString()));
      setTentativeAutomaton(updatedTentativeAutomaton);
    }
    if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){
      spin = new SpinUtil(config);
      SpinResult sr = spin.check(ptaHardFacts, ifthenAutomataAsText);
      if(!sr.isPass())
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, sr.getCounters()));
    }

    Stack<PairScore> possibleMerges = topLevelListener.ChooseStatePairs(getTentativeAutomaton());
    int iterations = 0, currentNonAmber = ptaHardFacts.getStateNumber()-ptaHardFacts.getAmberStateNumber();
    JUConstants colourToAugmentWith = getTentativeAutomaton().config.getUseAmber()? JUConstants.AMBER:null;
    updateGraph(getTentativeAutomaton(),ptaHardFacts);
    while (!possibleMerges.isEmpty())
    {
      iterations++;
      PairScore pair = possibleMerges.pop();
      final LearnerGraph temp = topLevelListener.MergeAndDeterminize(getTentativeAutomaton(), pair);
      Collection<List<Label>> questions = new LinkedList<List<Label>>();
      long score = pair.getScore();
      RestartLearningEnum restartLearning = RestartLearningEnum.restartNONE;// whether we need to rebuild a PTA and restart learning.

      if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){

        Collection<List<Label>> counterExamples = spin.check(temp, getTentativeAutomaton(), ifthenAutomataAsText).getCounters();
        Iterator<List<Label>> counterExampleIt = counterExamples.iterator();
        while(counterExampleIt.hasNext())
        {
          List<Label> counterExample = counterExampleIt.next();
          topLevelListener.AugmentPTA(ptaSoftFacts, RestartLearningEnum.restartSOFT, counterExample, false,colourToAugmentWith);
          System.out.println("<temp> "+counterExample);
         
        }
        if(counterExamples.size()>0)
          restartLearning = RestartLearningEnum.restartSOFT;
      }
     
      if (config.isUseConstraints())
      {
        LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
        StringBuffer counterExampleHolder = new StringBuffer();
        if (!topLevelListener.AddConstraints(temp,updatedTentativeAutomaton,counterExampleHolder))
        {
          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
          System.out.println("<info> pair "+pair+" contradicts constraints, hence recorded as incompatible");
        }
        // since we still need the outcome of merging to ask questions,
        // we delay actually performing augmentation until the time we are
        // finished with questions.
      }

      Iterator<List<Label>> questionIt = null;

      if (restartLearning == RestartLearningEnum.restartNONE)
      {
        Map<CmpVertex,JUConstants.PAIRCOMPATIBILITY> compatibilityMap = ptaHardFacts.pairCompatibility.compatibility.get(pair.getQ());
        if (pair.getScore() > config.getScoreForAutomergeUponRestart() && compatibilityMap != null && compatibilityMap.get(pair.getR()) == JUConstants.PAIRCOMPATIBILITY.MERGED)
          System.out.println("<automerge of previously merged pair> "+pair);
        else
        {
          // ask questions if needed
          if (shouldAskQuestions(score))
          {
            temp.setName(getGraphName()+"_"+iterations);
            //LearnerGraph updatedGraphActual = ComputeQuestions.constructGraphWithQuestions(pair, tentativeAutomaton, temp);
            //updatedGraphActual.setName(getGraphName(config)+"questions "+iterations);setChanged();updateGraph(updatedGraphActual,ptaHardFacts);
           
            questions = topLevelListener.ComputeQuestions(pair, getTentativeAutomaton(), temp);// all answers are considered "hard", hence we have to ask questions based on hard facts in order to avoid prefixes which are not valid in hard facts
            questionIt = questions.iterator();
            if (questionIt.hasNext())
            {
              pair.firstElem.setHighlight(true);
              pair.secondElem.setHighlight(true);
              updateGraph(getTentativeAutomaton(),ptaHardFacts);
              pair.firstElem.setHighlight(false);
              pair.secondElem.setHighlight(false);
            }
          }
        }
      }

      while (restartLearning == RestartLearningEnum.restartNONE && questionIt != null && questionIt.hasNext())
      {
        List<Label> question = questionIt.next();
       
        boolean accepted = pair.getQ().isAccept();
        Pair<Integer,String> answer = null;
        if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty())
          answer = new Pair<Integer,String>(spin.check(question, ifthenAutomataAsText),null);
       
        CmpVertex tempVertex = temp.getVertex(question);
        boolean answerFromSpin = false;
        if(answer != null && answer.firstElem >= 0)
          answerFromSpin = true;
        else
        {
          if (GlobalConfiguration.getConfiguration().isAssertEnabled())
            if (ptaHardFacts.paths.tracePathPrefixClosed(question) == AbstractOracle.USER_ACCEPTED) {
              throw new IllegalArgumentException("question "+ question+ " has already been answered");
            }
          List<Boolean> acceptedElements = PathRoutines.mapPathToConfirmedElements(ptaHardFacts,question,ifthenAutomata);

          answer = topLevelListener.CheckWithEndUser(getTentativeAutomaton(), question,
              tempVertex.isAccept()?AbstractOracle.USER_ACCEPTED:question.size() - 1,
                  acceptedElements, pair,
              new Object[] { "LTL","IFTHEN","IGNORE QUESTION","MARK AS INCOMPATIBLE","Add trace"});
        }
        if (answer.firstElem == AbstractOracle.USER_CANCELLED)
        {
          System.out.println("CANCELLED");
          return null;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_IGNORED)
        {// do nothing
          restartLearning = RestartLearningEnum.restartNONE;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_INCOMPATIBLE)
        {
          /* When autoanswers says that a particular pair is incompatible, <em>StoredAnswers</em> the answer refers to the current
           * question, but we have to return a pair which is incompatible. Although strange, it is not really surprising - the whole
           * AutoAnswers framework aims to automate debugging hence we are expected to go through the same sequence of questions
           * over and over again - it is enough to validate that we do not deviate and hence all that is necessary is to check that
           * the current pair to be merged is the same as the one recorded as incompatible when an answer was recorded.
           */

          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_NEWTRACE)
        {
          String traceDescr = answer.secondElem;
          boolean obtainedViaAuto = answer.secondElem != null;
          if (traceDescr == null) traceDescr = JOptionPane.showInputDialog("New trace :");
          if(traceDescr != null && traceDescr.length() != 0)
          {
            final JUConstants colour = colourToAugmentWith;
            final AtomicBoolean whetherToRestart = new AtomicBoolean(false);
            QSMTool.parseSequenceOfTraces(traceDescr, config, new TraceAdder() {

              @Override
              public void addTrace(List<Label> trace,  boolean positive) {
                if (positive) extraTracesPlus.add(trace);else extraTracesMinus.add(trace);
                CmpVertex tailVertex = temp.getVertex(trace);
                if (tailVertex != null && tailVertex.isAccept() != positive)
                  whetherToRestart.set(true);
              }
             
            }, getLabelConverter());
         
            if (!obtainedViaAuto) System.out.println(RPNILearner.QUESTION_USER+" "+question.toString()+" "+RPNILearner.QUESTION_NEWTRACE+" "+traceDescr);
            // At this point, we attempt to augment the current automaton with the supplied traces,
            // which may be successful or not (if we did some erroneous mergers earlier), in which case we restart.

                  for(List<Label> positive:extraTracesPlus)
                    AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,positive, true,colour);
            for(List<Label> negative:extraTracesMinus)
              AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,negative, false,colour);
           
            if (whetherToRestart.get())
              restartLearning = RestartLearningEnum.restartHARD;// we've seen at least one trace which contradicts the new tentative PTA.
            else
              restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;// the set of questions will be rebuilt because we possibly modified the "nonexistent" PTA containing questions.
          }
        }
        else
        if (answer.firstElem == AbstractOracle.USER_ACCEPTED)
        {
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,question, true,colourToAugmentWith);
         
          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,question, true,colourToAugmentWith);

          if (!tempVertex.isAccept())
          {// contradiction with the result of merging
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
        if (answer.firstElem >= 0)
        {// The sequence has been rejected by a user
          assert answer.firstElem < question.size();
          LinkedList<Label> subAnswer = new LinkedList<Label>();
          subAnswer.addAll(question.subList(0, answer.firstElem + 1));
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts, RestartLearningEnum.restartHARD,subAnswer, false,colourToAugmentWith);

          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,subAnswer, false,colourToAugmentWith);
          // important: since vertex IDs is
          // only unique for each instance of ComputeStateScores, only
          // one instance should ever receive calls to augmentPTA

          if ((answer.firstElem < question.size() - 1) || tempVertex.isAccept())
          {// contradiction with the result of merging
            assert accepted == true;
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
          if(answer.firstElem == AbstractOracle.USER_LTL || answer.firstElem == AbstractOracle.USER_IFTHEN)
          {
            String answerType = null;
            if (answer.firstElem == AbstractOracle.USER_LTL)
              answerType = QSMTool.cmdLTL;
            else
              if (answer.firstElem == AbstractOracle.USER_IFTHEN)
                answerType = QSMTool.cmdIFTHENAUTOMATON;
              else
                throw new IllegalArgumentException("unexpected user choice kind "+answer.firstElem);

            restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;
            String addedConstraint = answer.secondElem;
            boolean obtainedLTLViaAuto = addedConstraint != null;
            if (addedConstraint == null) addedConstraint = JOptionPane.showInputDialog("New "+answerType+" formula:");
            if(addedConstraint != null && addedConstraint.length() != 0)
            {
              if (!obtainedLTLViaAuto) System.out.println(QUESTION_USER+" "+question.toString()+ " <"+answerType+"> "+addedConstraint);
              Set<String> tmpLtl = new HashSet<String>();tmpLtl.addAll(ifthenAutomataAsText);tmpLtl.add(answerType+" "+addedConstraint);
              if(!config.isUseConstraints())
              {
                Collection<List<Label>> counters = spin.check(ptaHardFacts, tmpLtl).getCounters();
                if (counters.size()>0)
                {
                  String errorMessage = getHardFactsContradictionErrorMessage(tmpLtl, counters);
                  if (obtainedLTLViaAuto) // cannot recover from autosetting, otherwise warn a user
                    throw new IllegalArgumentException(errorMessage);
View Full Code Here

  @Override
  public LearnerGraph learnMachine()
  {
    final Configuration shallowCopy = getTentativeAutomaton().config.copy();shallowCopy.setLearnerCloneGraph(false);
    ptaHardFacts = new LearnerGraph(shallowCopy);// this is now cloned to eliminate counter-examples added to ptaSoftFacts by Spin
    SpinUtil spin = null;
    LearnerGraph.copyGraphs(getTentativeAutomaton(), ptaHardFacts);
    LearnerGraph ptaSoftFacts = getTentativeAutomaton();
    setChanged();getTentativeAutomaton().setName(getGraphName()+"_init");
    final List<List<Label>> extraTracesPlus = new LinkedList<List<Label>>(), extraTracesMinus = new LinkedList<List<Label>>();
   
    if (config.isUseConstraints())
    {
      LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
      StringBuffer counterExampleHolder = new StringBuffer();
      if (ifthenAutomata == null) ifthenAutomata = Transform.buildIfThenAutomata(ifthenAutomataAsText, ptaHardFacts, config).toArray(new LearnerGraph[0]);

      if (!topLevelListener.AddConstraints(getTentativeAutomaton(),updatedTentativeAutomaton,counterExampleHolder))
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, counterExampleHolder.toString()));
      setTentativeAutomaton(updatedTentativeAutomaton);
    }
    if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){
      spin = new SpinUtil(config);
      SpinResult sr = spin.check(ptaHardFacts, ifthenAutomataAsText);
      if(!sr.isPass())
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, sr.getCounters()));
    }

    Stack<PairScore> possibleMerges = topLevelListener.ChooseStatePairs(getTentativeAutomaton());
    int iterations = 0, currentNonAmber = ptaHardFacts.getStateNumber()-ptaHardFacts.getAmberStateNumber();
    JUConstants colourToAugmentWith = getTentativeAutomaton().config.getUseAmber()? JUConstants.AMBER:null;
    updateGraph(getTentativeAutomaton(),ptaHardFacts);
    while (!possibleMerges.isEmpty())
    {
      iterations++;
      PairScore pair = possibleMerges.pop();
      final LearnerGraph temp = topLevelListener.MergeAndDeterminize(getTentativeAutomaton(), pair);
      Collection<List<Label>> questions = new LinkedList<List<Label>>();
      long score = pair.getScore();
      RestartLearningEnum restartLearning = RestartLearningEnum.restartNONE;// whether we need to rebuild a PTA and restart learning.

      if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){

        Collection<List<Label>> counterExamples = spin.check(temp, getTentativeAutomaton(), ifthenAutomataAsText).getCounters();
        Iterator<List<Label>> counterExampleIt = counterExamples.iterator();
        while(counterExampleIt.hasNext())
        {
          List<Label> counterExample = counterExampleIt.next();
          topLevelListener.AugmentPTA(ptaSoftFacts, RestartLearningEnum.restartSOFT, counterExample, false,colourToAugmentWith);
          System.out.println("<temp> "+counterExample);
         
        }
        if(counterExamples.size()>0)
          restartLearning = RestartLearningEnum.restartSOFT;
      }
     
      if (config.isUseConstraints())
      {
        LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
        StringBuffer counterExampleHolder = new StringBuffer();
        if (!topLevelListener.AddConstraints(temp,updatedTentativeAutomaton,counterExampleHolder))
        {
          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
          System.out.println("<info> pair "+pair+" contradicts constraints, hence recorded as incompatible");
        }
        // since we still need the outcome of merging to ask questions,
        // we delay actually performing augmentation until the time we are
        // finished with questions.
      }

      Iterator<List<Label>> questionIt = null;

      if (restartLearning == RestartLearningEnum.restartNONE)
      {
        Map<CmpVertex,JUConstants.PAIRCOMPATIBILITY> compatibilityMap = ptaHardFacts.pairCompatibility.compatibility.get(pair.getQ());
        if (pair.getScore() > config.getScoreForAutomergeUponRestart() && compatibilityMap != null && compatibilityMap.get(pair.getR()) == JUConstants.PAIRCOMPATIBILITY.MERGED)
          System.out.println("<automerge of previously merged pair> "+pair);
        else
        {
          // ask questions if needed
          if (shouldAskQuestions(score))
          {
            temp.setName(getGraphName()+"_"+iterations);
            //LearnerGraph updatedGraphActual = ComputeQuestions.constructGraphWithQuestions(pair, tentativeAutomaton, temp);
            //updatedGraphActual.setName(getGraphName(config)+"questions "+iterations);setChanged();updateGraph(updatedGraphActual,ptaHardFacts);
           
            questions = topLevelListener.ComputeQuestions(pair, getTentativeAutomaton(), temp);// all answers are considered "hard", hence we have to ask questions based on hard facts in order to avoid prefixes which are not valid in hard facts
            questionIt = questions.iterator();
            if (questionIt.hasNext())
            {
              pair.firstElem.setHighlight(true);
              pair.secondElem.setHighlight(true);
              updateGraph(getTentativeAutomaton(),ptaHardFacts);
              pair.firstElem.setHighlight(false);
              pair.secondElem.setHighlight(false);
            }
          }
        }
      }

      while (restartLearning == RestartLearningEnum.restartNONE && questionIt != null && questionIt.hasNext())
      {
        List<Label> question = questionIt.next();
       
        boolean accepted = pair.getQ().isAccept();
        Pair<Integer,String> answer = null;
        if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty())
          answer = new Pair<Integer,String>(spin.check(question, ifthenAutomataAsText),null);
       
        CmpVertex tempVertex = temp.getVertex(question);
        boolean answerFromSpin = false;
        if(answer != null && answer.firstElem >= 0)
          answerFromSpin = true;
        else
        {
          if (Boolean.valueOf(GlobalConfiguration.getConfiguration().getProperty(GlobalConfiguration.G_PROPERTIES.ASSERT)))
            if (ptaHardFacts.paths.tracePathPrefixClosed(question) == AbstractOracle.USER_ACCEPTED) {
              throw new IllegalArgumentException("question "+ question+ " has already been answered");
            }
          List<Boolean> acceptedElements = PathRoutines.mapPathToConfirmedElements(ptaHardFacts,question,ifthenAutomata);

          answer = topLevelListener.CheckWithEndUser(getTentativeAutomaton(), question,
              tempVertex.isAccept()?AbstractOracle.USER_ACCEPTED:question.size() - 1,
                  acceptedElements, pair,
              new Object[] { "LTL","IFTHEN","IGNORE QUESTION","MARK AS INCOMPATIBLE","Add trace"});
        }
        if (answer.firstElem == AbstractOracle.USER_CANCELLED)
        {
          System.out.println("CANCELLED");
          return null;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_IGNORED)
        {// do nothing
          restartLearning = RestartLearningEnum.restartNONE;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_INCOMPATIBLE)
        {
          /* When autoanswers says that a particular pair is incompatible, <em>StoredAnswers</em> the answer refers to the current
           * question, but we have to return a pair which is incompatible. Although strange, it is not really surprising - the whole
           * AutoAnswers framework aims to automate debugging hence we are expected to go through the same sequence of questions
           * over and over again - it is enough to validate that we do not deviate and hence all that is necessary is to check that
           * the current pair to be merged is the same as the one recorded as incompatible when an answer was recorded.
           */

          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_NEWTRACE)
        {
          String traceDescr = answer.secondElem;
          boolean obtainedViaAuto = answer.secondElem != null;
          if (traceDescr == null) traceDescr = JOptionPane.showInputDialog("New trace :");
          if(traceDescr != null && traceDescr.length() != 0)
          {
            final JUConstants colour = colourToAugmentWith;
            final AtomicBoolean whetherToRestart = new AtomicBoolean(false);
            QSMTool.parseSequenceOfTraces(traceDescr, config, new TraceAdder() {

              @Override
              public void addTrace(List<Label> trace,  boolean positive) {
                if (positive) extraTracesPlus.add(trace);else extraTracesMinus.add(trace);
                CmpVertex tailVertex = temp.getVertex(trace);
                if (tailVertex != null && tailVertex.isAccept() != positive)
                  whetherToRestart.set(true);
              }
             
            });
         
            if (!obtainedViaAuto) System.out.println(RPNILearner.QUESTION_USER+" "+question.toString()+" "+RPNILearner.QUESTION_NEWTRACE+" "+traceDescr);
            // At this point, we attempt to augment the current automaton with the supplied traces,
            // which may be successful or not (if we did some erroneous mergers earlier), in which case we restart.

                  for(List<Label> positive:extraTracesPlus)
                    AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,positive, true,colour);
            for(List<Label> negative:extraTracesMinus)
              AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,negative, false,colour);
           
            if (whetherToRestart.get())
              restartLearning = RestartLearningEnum.restartHARD;// we've seen at least one trace which contradicts the new tentative PTA.
            else
              restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;// the set of questions will be rebuilt because we possibly modified the "nonexistent" PTA containing questions.
          }
        }
        else
        if (answer.firstElem == AbstractOracle.USER_ACCEPTED)
        {
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,question, true,colourToAugmentWith);
         
          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,question, true,colourToAugmentWith);

          if (!tempVertex.isAccept())
          {// contradiction with the result of merging
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
        if (answer.firstElem >= 0)
        {// The sequence has been rejected by a user
          assert answer.firstElem < question.size();
          LinkedList<Label> subAnswer = new LinkedList<Label>();
          subAnswer.addAll(question.subList(0, answer.firstElem + 1));
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts, RestartLearningEnum.restartHARD,subAnswer, false,colourToAugmentWith);

          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,subAnswer, false,colourToAugmentWith);
          // important: since vertex IDs is
          // only unique for each instance of ComputeStateScores, only
          // one instance should ever receive calls to augmentPTA

          if ((answer.firstElem < question.size() - 1) || tempVertex.isAccept())
          {// contradiction with the result of merging
            assert accepted == true;
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
          if(answer.firstElem == AbstractOracle.USER_LTL || answer.firstElem == AbstractOracle.USER_IFTHEN)
          {
            String answerType = null;
            if (answer.firstElem == AbstractOracle.USER_LTL)
              answerType = QSMTool.cmdLTL;
            else
              if (answer.firstElem == AbstractOracle.USER_IFTHEN)
                answerType = QSMTool.cmdIFTHENAUTOMATON;
              else
                throw new IllegalArgumentException("unexpected user choice kind "+answer.firstElem);

            restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;
            String addedConstraint = answer.secondElem;
            boolean obtainedLTLViaAuto = addedConstraint != null;
            if (addedConstraint == null) addedConstraint = JOptionPane.showInputDialog("New "+answerType+" formula:");
            if(addedConstraint != null && addedConstraint.length() != 0)
            {
              if (!obtainedLTLViaAuto) System.out.println(QUESTION_USER+" "+question.toString()+ " <"+answerType+"> "+addedConstraint);
              Set<String> tmpLtl = new HashSet<String>();tmpLtl.addAll(ifthenAutomataAsText);tmpLtl.add(answerType+" "+addedConstraint);
              if(!config.isUseConstraints())
              {
                Collection<List<Label>> counters = spin.check(ptaHardFacts, tmpLtl).getCounters();
                if (counters.size()>0)
                {
                  String errorMessage = getHardFactsContradictionErrorMessage(tmpLtl, counters);
                  if (obtainedLTLViaAuto) // cannot recover from autosetting, otherwise warn a user
                    throw new IllegalArgumentException(errorMessage);
View Full Code Here

  @Override
  public LearnerGraph learnMachine()
  {
    final Configuration shallowCopy = getTentativeAutomaton().config.copy();shallowCopy.setLearnerCloneGraph(false);
    ptaHardFacts = new LearnerGraph(shallowCopy);// this is now cloned to eliminate counter-examples added to ptaSoftFacts by Spin
    SpinUtil spin = null;
    LearnerGraph.copyGraphs(getTentativeAutomaton(), ptaHardFacts);
    LearnerGraph ptaSoftFacts = getTentativeAutomaton();
    setChanged();getTentativeAutomaton().setName(getGraphName()+"_init");
    final List<List<Label>> extraTracesPlus = new LinkedList<List<Label>>(), extraTracesMinus = new LinkedList<List<Label>>();

    if (config.isUseConstraints())
    {
      LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
      StringBuffer counterExampleHolder = new StringBuffer();
      if (ifthenAutomata == null)
        ifthenAutomata = Transform.buildIfThenAutomata(ifthenAutomataAsText, ptaHardFacts, config, getLabelConverter()).toArray(new LearnerGraph[0]);

      if (!topLevelListener.AddConstraints(getTentativeAutomaton(),updatedTentativeAutomaton,counterExampleHolder))
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, counterExampleHolder.toString()));
      setTentativeAutomaton(updatedTentativeAutomaton);
    }
    if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){
      spin = new SpinUtil(config);
      SpinResult sr = spin.check(ptaHardFacts, ifthenAutomataAsText);
      if(!sr.isPass())
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, sr.getCounters()));
    }

    Stack<PairScore> possibleMerges = topLevelListener.ChooseStatePairs(getTentativeAutomaton());
    int iterations = 0, currentNonAmber = ptaHardFacts.getStateNumber()-ptaHardFacts.getAmberStateNumber();
    JUConstants colourToAugmentWith = getTentativeAutomaton().config.getUseAmber()? JUConstants.AMBER:null;
    updateGraph(getTentativeAutomaton(),ptaHardFacts);
    while (!possibleMerges.isEmpty())
    {
      iterations++;
      PairScore pair = possibleMerges.pop();
      final LearnerGraph temp = topLevelListener.MergeAndDeterminize(getTentativeAutomaton(), pair);
      Collection<List<Label>> questions = new LinkedList<List<Label>>();
      long score = pair.getScore();
      RestartLearningEnum restartLearning = RestartLearningEnum.restartNONE;// whether we need to rebuild a PTA and restart learning.

      if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){

        Collection<List<Label>> counterExamples = spin.check(temp, getTentativeAutomaton(), ifthenAutomataAsText).getCounters();
        Iterator<List<Label>> counterExampleIt = counterExamples.iterator();
        while(counterExampleIt.hasNext())
        {
          List<Label> counterExample = counterExampleIt.next();
          topLevelListener.AugmentPTA(ptaSoftFacts, RestartLearningEnum.restartSOFT, counterExample, false,colourToAugmentWith);
          System.out.println("<temp> "+counterExample);
         
        }
        if(counterExamples.size()>0)
          restartLearning = RestartLearningEnum.restartSOFT;
      }
     
      if (config.isUseConstraints())
      {
        LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
        StringBuffer counterExampleHolder = new StringBuffer();
        if (!topLevelListener.AddConstraints(temp,updatedTentativeAutomaton,counterExampleHolder))
        {
          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
          System.out.println("<info> pair "+pair+" contradicts constraints, hence recorded as incompatible");
        }
        // since we still need the outcome of merging to ask questions,
        // we delay actually performing augmentation until the time we are
        // finished with questions.
      }

      Iterator<List<Label>> questionIt = null;

      if (restartLearning == RestartLearningEnum.restartNONE)
      {
        Map<CmpVertex,JUConstants.PAIRCOMPATIBILITY> compatibilityMap = ptaHardFacts.pairCompatibility.compatibility.get(pair.getQ());
        if (pair.getScore() > config.getScoreForAutomergeUponRestart() && compatibilityMap != null && compatibilityMap.get(pair.getR()) == JUConstants.PAIRCOMPATIBILITY.MERGED)
          System.out.println("<automerge of previously merged pair> "+pair);
        else
        {
          // ask questions if needed
          if (shouldAskQuestions(score))
          {
            temp.setName(getGraphName()+"_"+iterations);
            //LearnerGraph updatedGraphActual = ComputeQuestions.constructGraphWithQuestions(pair, tentativeAutomaton, temp);
            //updatedGraphActual.setName(getGraphName(config)+"questions "+iterations);setChanged();updateGraph(updatedGraphActual,ptaHardFacts);
           
            questions = topLevelListener.ComputeQuestions(pair, getTentativeAutomaton(), temp);// all answers are considered "hard", hence we have to ask questions based on hard facts in order to avoid prefixes which are not valid in hard facts
            questionIt = questions.iterator();
            if (questionIt.hasNext())
            {
              pair.firstElem.setHighlight(true);
              pair.secondElem.setHighlight(true);
              updateGraph(getTentativeAutomaton(),ptaHardFacts);
              pair.firstElem.setHighlight(false);
              pair.secondElem.setHighlight(false);
            }
          }
        }
      }

      while (restartLearning == RestartLearningEnum.restartNONE && questionIt != null && questionIt.hasNext())
      {
        List<Label> question = questionIt.next();
       
        boolean accepted = pair.getQ().isAccept();
        Pair<Integer,String> answer = null;
        if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty())
          answer = new Pair<Integer,String>(spin.check(question, ifthenAutomataAsText),null);
       
        CmpVertex tempVertex = temp.getVertex(question);
        boolean answerFromSpin = false;
        if(answer != null && answer.firstElem >= 0)
          answerFromSpin = true;
        else
        {
          if (Boolean.valueOf(GlobalConfiguration.getConfiguration().getProperty(GlobalConfiguration.G_PROPERTIES.ASSERT_ENABLED)))
            if (ptaHardFacts.paths.tracePathPrefixClosed(question) == AbstractOracle.USER_ACCEPTED) {
              throw new IllegalArgumentException("question "+ question+ " has already been answered");
            }
          List<Boolean> acceptedElements = PathRoutines.mapPathToConfirmedElements(ptaHardFacts,question,ifthenAutomata);

          answer = topLevelListener.CheckWithEndUser(getTentativeAutomaton(), question,
              tempVertex.isAccept()?AbstractOracle.USER_ACCEPTED:question.size() - 1,
                  acceptedElements, pair,
              new Object[] { "LTL","IFTHEN","IGNORE QUESTION","MARK AS INCOMPATIBLE","Add trace"});
        }
        if (answer.firstElem == AbstractOracle.USER_CANCELLED)
        {
          System.out.println("CANCELLED");
          return null;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_IGNORED)
        {// do nothing
          restartLearning = RestartLearningEnum.restartNONE;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_INCOMPATIBLE)
        {
          /* When autoanswers says that a particular pair is incompatible, <em>StoredAnswers</em> the answer refers to the current
           * question, but we have to return a pair which is incompatible. Although strange, it is not really surprising - the whole
           * AutoAnswers framework aims to automate debugging hence we are expected to go through the same sequence of questions
           * over and over again - it is enough to validate that we do not deviate and hence all that is necessary is to check that
           * the current pair to be merged is the same as the one recorded as incompatible when an answer was recorded.
           */

          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_NEWTRACE)
        {
          String traceDescr = answer.secondElem;
          boolean obtainedViaAuto = answer.secondElem != null;
          if (traceDescr == null) traceDescr = JOptionPane.showInputDialog("New trace :");
          if(traceDescr != null && traceDescr.length() != 0)
          {
            final JUConstants colour = colourToAugmentWith;
            final AtomicBoolean whetherToRestart = new AtomicBoolean(false);
            QSMTool.parseSequenceOfTraces(traceDescr, config, new TraceAdder() {

              @Override
              public void addTrace(List<Label> trace,  boolean positive) {
                if (positive) extraTracesPlus.add(trace);else extraTracesMinus.add(trace);
                CmpVertex tailVertex = temp.getVertex(trace);
                if (tailVertex != null && tailVertex.isAccept() != positive)
                  whetherToRestart.set(true);
              }
             
            });
         
            if (!obtainedViaAuto) System.out.println(RPNILearner.QUESTION_USER+" "+question.toString()+" "+RPNILearner.QUESTION_NEWTRACE+" "+traceDescr);
            // At this point, we attempt to augment the current automaton with the supplied traces,
            // which may be successful or not (if we did some erroneous mergers earlier), in which case we restart.

                  for(List<Label> positive:extraTracesPlus)
                    AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,positive, true,colour);
            for(List<Label> negative:extraTracesMinus)
              AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,negative, false,colour);
           
            if (whetherToRestart.get())
              restartLearning = RestartLearningEnum.restartHARD;// we've seen at least one trace which contradicts the new tentative PTA.
            else
              restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;// the set of questions will be rebuilt because we possibly modified the "nonexistent" PTA containing questions.
          }
        }
        else
        if (answer.firstElem == AbstractOracle.USER_ACCEPTED)
        {
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,question, true,colourToAugmentWith);
         
          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,question, true,colourToAugmentWith);

          if (!tempVertex.isAccept())
          {// contradiction with the result of merging
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
        if (answer.firstElem >= 0)
        {// The sequence has been rejected by a user
          assert answer.firstElem < question.size();
          LinkedList<Label> subAnswer = new LinkedList<Label>();
          subAnswer.addAll(question.subList(0, answer.firstElem + 1));
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts, RestartLearningEnum.restartHARD,subAnswer, false,colourToAugmentWith);

          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,subAnswer, false,colourToAugmentWith);
          // important: since vertex IDs is
          // only unique for each instance of ComputeStateScores, only
          // one instance should ever receive calls to augmentPTA

          if ((answer.firstElem < question.size() - 1) || tempVertex.isAccept())
          {// contradiction with the result of merging
            assert accepted == true;
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
          if(answer.firstElem == AbstractOracle.USER_LTL || answer.firstElem == AbstractOracle.USER_IFTHEN)
          {
            String answerType = null;
            if (answer.firstElem == AbstractOracle.USER_LTL)
              answerType = QSMTool.cmdLTL;
            else
              if (answer.firstElem == AbstractOracle.USER_IFTHEN)
                answerType = QSMTool.cmdIFTHENAUTOMATON;
              else
                throw new IllegalArgumentException("unexpected user choice kind "+answer.firstElem);

            restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;
            String addedConstraint = answer.secondElem;
            boolean obtainedLTLViaAuto = addedConstraint != null;
            if (addedConstraint == null) addedConstraint = JOptionPane.showInputDialog("New "+answerType+" formula:");
            if(addedConstraint != null && addedConstraint.length() != 0)
            {
              if (!obtainedLTLViaAuto) System.out.println(QUESTION_USER+" "+question.toString()+ " <"+answerType+"> "+addedConstraint);
              Set<String> tmpLtl = new HashSet<String>();tmpLtl.addAll(ifthenAutomataAsText);tmpLtl.add(answerType+" "+addedConstraint);
              if(!config.isUseConstraints())
              {
                Collection<List<Label>> counters = spin.check(ptaHardFacts, tmpLtl).getCounters();
                if (counters.size()>0)
                {
                  String errorMessage = getHardFactsContradictionErrorMessage(tmpLtl, counters);
                  if (obtainedLTLViaAuto) // cannot recover from autosetting, otherwise warn a user
                    throw new IllegalArgumentException(errorMessage);
View Full Code Here

  @Override
  public LearnerGraph learnMachine()
  {
    final Configuration shallowCopy = getTentativeAutomaton().config.copy();shallowCopy.setLearnerCloneGraph(false);
    ptaHardFacts = new LearnerGraph(shallowCopy);// this is now cloned to eliminate counter-examples added to ptaSoftFacts by Spin
    SpinUtil spin = null;
    LearnerGraph.copyGraphs(getTentativeAutomaton(), ptaHardFacts);
    LearnerGraph ptaSoftFacts = getTentativeAutomaton();
    setChanged();getTentativeAutomaton().setName(getGraphName()+"_init");
    final List<List<Label>> extraTracesPlus = new LinkedList<List<Label>>(), extraTracesMinus = new LinkedList<List<Label>>();

    if (config.isUseConstraints())
    {
      LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
      StringBuffer counterExampleHolder = new StringBuffer();
      if (ifthenAutomata == null)
        ifthenAutomata = Transform.buildIfThenAutomata(ifthenAutomataAsText, alphabetUsedForIfThen, ptaHardFacts, config, topLevelListener.getLabelConverter()).toArray(new LearnerGraph[0]);

      if (!topLevelListener.AddConstraints(getTentativeAutomaton(),updatedTentativeAutomaton,counterExampleHolder))
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, counterExampleHolder.toString()));
      setTentativeAutomaton(updatedTentativeAutomaton);
    }
    if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){
      spin = new SpinUtil(config,getLabelConverter());
      SpinResult sr = spin.check(ptaHardFacts, ifthenAutomataAsText);
      if(!sr.isPass())
        throw new IllegalArgumentException(getHardFactsContradictionErrorMessage(ifthenAutomataAsText, sr.getCounters()));
    }

    Stack<PairScore> possibleMerges = topLevelListener.ChooseStatePairs(getTentativeAutomaton());
    int iterations = 0, currentNonAmber = ptaHardFacts.getStateNumber()-ptaHardFacts.getAmberStateNumber();
    JUConstants colourToAugmentWith = getTentativeAutomaton().config.getUseAmber()? JUConstants.AMBER:null;
    updateGraph(getTentativeAutomaton(),ptaHardFacts);
    while (!possibleMerges.isEmpty())
    {
      iterations++;
      PairScore pair = possibleMerges.pop();
      final LearnerGraph temp = topLevelListener.MergeAndDeterminize(getTentativeAutomaton(), pair);
      Collection<List<Label>> questions = new LinkedList<List<Label>>();
      long score = pair.getScore();
      RestartLearningEnum restartLearning = RestartLearningEnum.restartNONE;// whether we need to rebuild a PTA and restart learning.

      if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty()){

        Collection<List<Label>> counterExamples = spin.check(temp, getTentativeAutomaton(), ifthenAutomataAsText).getCounters();
        Iterator<List<Label>> counterExampleIt = counterExamples.iterator();
        while(counterExampleIt.hasNext())
        {
          List<Label> counterExample = counterExampleIt.next();
          topLevelListener.AugmentPTA(ptaSoftFacts, RestartLearningEnum.restartSOFT, counterExample, false,colourToAugmentWith);
          System.out.println("<temp> "+counterExample);
         
        }
        if(counterExamples.size()>0)
          restartLearning = RestartLearningEnum.restartSOFT;
      }

      if (config.isUseConstraints())
      {
        LearnerGraph updatedTentativeAutomaton = new LearnerGraph(shallowCopy);
        StringBuffer counterExampleHolder = new StringBuffer();
        if (!topLevelListener.AddConstraints(temp,updatedTentativeAutomaton,counterExampleHolder))
        {
          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
          System.out.println("<info> pair "+pair+" contradicts constraints, hence recorded as incompatible");
        }
        // since we still need the outcome of merging to ask questions,
        // we delay actually performing augmentation until the time we are
        // finished with questions.
      }

      Iterator<List<Label>> questionIt = null;

      if (restartLearning == RestartLearningEnum.restartNONE)
      {
        Map<CmpVertex,JUConstants.PAIRCOMPATIBILITY> compatibilityMap = ptaHardFacts.pairCompatibility.compatibility.get(pair.getQ());
        if (pair.getScore() > config.getScoreForAutomergeUponRestart() && compatibilityMap != null && compatibilityMap.get(pair.getR()) == JUConstants.PAIRCOMPATIBILITY.MERGED)
          System.out.println("<automerge of previously merged pair> "+pair);
        else
        {
          // ask questions if needed
          if (shouldAskQuestions(score))
          {
            temp.setName(getGraphName()+"_"+iterations);
            //LearnerGraph updatedGraphActual = ComputeQuestions.constructGraphWithQuestions(pair, tentativeAutomaton, temp);
            //updatedGraphActual.setName(getGraphName(config)+"questions "+iterations);setChanged();updateGraph(updatedGraphActual,ptaHardFacts);
           
            questions = topLevelListener.ComputeQuestions(pair, getTentativeAutomaton(), temp);// all answers are considered "hard", hence we have to ask questions based on hard facts in order to avoid prefixes which are not valid in hard facts
            questionIt = questions.iterator();
            if (questionIt.hasNext())
            {
              pair.firstElem.setHighlight(true);
              pair.secondElem.setHighlight(true);
              updateGraph(getTentativeAutomaton(),ptaHardFacts);
              pair.firstElem.setHighlight(false);
              pair.secondElem.setHighlight(false);
            }
          }
        }
      }

      while (restartLearning == RestartLearningEnum.restartNONE && questionIt != null && questionIt.hasNext())
      {
        List<Label> question = questionIt.next();
       
        boolean accepted = pair.getQ().isAccept();
        Pair<Integer,String> answer = null;
        if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin() && !ifthenAutomataAsText.isEmpty())
          answer = new Pair<Integer,String>(spin.check(question, ifthenAutomataAsText),null);
       
        CmpVertex tempVertex = temp.getVertex(question);
        boolean answerFromSpin = false;
        if(answer != null && answer.firstElem >= 0)
          answerFromSpin = true;
        else
        {
          if (GlobalConfiguration.getConfiguration().isAssertEnabled())
            if (ptaHardFacts.paths.tracePathPrefixClosed(question) == AbstractOracle.USER_ACCEPTED) {
              throw new IllegalArgumentException("question "+ question+ " has already been answered");
            }
          List<Boolean> acceptedElements = PathRoutines.mapPathToConfirmedElements(ptaHardFacts,question,ifthenAutomata);

          answer = topLevelListener.CheckWithEndUser(getTentativeAutomaton(), question,
              tempVertex.isAccept()?AbstractOracle.USER_ACCEPTED:question.size() - 1,
                  acceptedElements, pair,
              new Object[] { "LTL","IFTHEN","IGNORE QUESTION","MARK AS INCOMPATIBLE","Add trace"});
        }
        if (answer.firstElem == AbstractOracle.USER_CANCELLED)
        {
          System.out.println("CANCELLED");
          return null;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_IGNORED)
        {// do nothing
          restartLearning = RestartLearningEnum.restartNONE;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_INCOMPATIBLE)
        {
          /* When autoanswers says that a particular pair is incompatible, <em>StoredAnswers</em> the answer refers to the current
           * question, but we have to return a pair which is incompatible. Although strange, it is not really surprising - the whole
           * AutoAnswers framework aims to automate debugging hence we are expected to go through the same sequence of questions
           * over and over again - it is enough to validate that we do not deviate and hence all that is necessary is to check that
           * the current pair to be merged is the same as the one recorded as incompatible when an answer was recorded.
           */

          getTentativeAutomaton().addToCompatibility(pair.firstElem, pair.secondElem, PAIRCOMPATIBILITY.INCOMPATIBLE);
          restartLearning = RestartLearningEnum.restartRECOMPUTEPAIRS;
        }
        else
        if (answer.firstElem == AbstractOracle.USER_NEWTRACE)
        {
          String traceDescr = answer.secondElem;
          boolean obtainedViaAuto = answer.secondElem != null;
          if (traceDescr == null) traceDescr = JOptionPane.showInputDialog("New trace :");
          if(traceDescr != null && traceDescr.length() != 0)
          {
            final JUConstants colour = colourToAugmentWith;
            final AtomicBoolean whetherToRestart = new AtomicBoolean(false);
            QSMTool.parseSequenceOfTraces(traceDescr, config, new TraceAdder() {

              @Override
              public void addTrace(List<Label> trace,  boolean positive) {
                if (positive) extraTracesPlus.add(trace);else extraTracesMinus.add(trace);
                CmpVertex tailVertex = temp.getVertex(trace);
                if (tailVertex != null && tailVertex.isAccept() != positive)
                  whetherToRestart.set(true);
              }

            }, getLabelConverter());

            if (!obtainedViaAuto) System.out.println(RPNILearner.QUESTION_USER+" "+question.toString()+" "+RPNILearner.QUESTION_NEWTRACE+" "+traceDescr);
            // At this point, we attempt to augment the current automaton with the supplied traces,
            // which may be successful or not (if we did some erroneous mergers earlier), in which case we restart.

                  for(List<Label> positive:extraTracesPlus)
                    AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,positive, true,colour);
            for(List<Label> negative:extraTracesMinus)
              AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,negative, false,colour);
           
            if (whetherToRestart.get())
              restartLearning = RestartLearningEnum.restartHARD;// we've seen at least one trace which contradicts the new tentative PTA.
            else
              restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;// the set of questions will be rebuilt because we possibly modified the "nonexistent" PTA containing questions.
          }
        }
        else
        if (answer.firstElem == AbstractOracle.USER_ACCEPTED)
        {
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts,RestartLearningEnum.restartHARD,question, true,colourToAugmentWith);
         
          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,question, true,colourToAugmentWith);

          if (!tempVertex.isAccept())
          {// contradiction with the result of merging
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
        if (answer.firstElem >= 0)
        {// The sequence has been rejected by a user
          assert answer.firstElem < question.size();
          LinkedList<Label> subAnswer = new LinkedList<Label>();
          subAnswer.addAll(question.subList(0, answer.firstElem + 1));
          if(!answerFromSpin) // only add to hard facts when obtained directly from a user or from autofile
            AugumentPTA_and_QuestionPTA(ptaHardFacts, RestartLearningEnum.restartHARD,subAnswer, false,colourToAugmentWith);

          if (getTentativeAutomaton().config.getUseLTL() && getTentativeAutomaton().config.getUseSpin()) topLevelListener.AugmentPTA(ptaSoftFacts,RestartLearningEnum.restartSOFT,subAnswer, false,colourToAugmentWith);
          // important: since vertex IDs is
          // only unique for each instance of ComputeStateScores, only
          // one instance should ever receive calls to augmentPTA

          if ((answer.firstElem < question.size() - 1) || tempVertex.isAccept())
          {// contradiction with the result of merging
            assert accepted == true;
            if(!answerFromSpin)
              restartLearning = RestartLearningEnum.restartHARD;
            else
              restartLearning = RestartLearningEnum.restartSOFT;
           
          }
        }
        else
          if(answer.firstElem == AbstractOracle.USER_LTL || answer.firstElem == AbstractOracle.USER_IFTHEN)
          {
            String answerType = null;
            if (answer.firstElem == AbstractOracle.USER_LTL)
              answerType = QSMTool.cmdLTL;
            else
              if (answer.firstElem == AbstractOracle.USER_IFTHEN)
                answerType = QSMTool.cmdIFTHENAUTOMATON;
              else
                throw new IllegalArgumentException("unexpected user choice kind "+answer.firstElem);

            restartLearning = RestartLearningEnum.restartRECOMPUTEQUESTIONS;
            String addedConstraint = answer.secondElem;
            boolean obtainedLTLViaAuto = addedConstraint != null;
            if (addedConstraint == null) addedConstraint = JOptionPane.showInputDialog("New "+answerType+" formula:");
            if(addedConstraint != null && addedConstraint.length() != 0)
            {
              if (!obtainedLTLViaAuto) System.out.println(QUESTION_USER+" "+question.toString()+ " <"+answerType+"> "+addedConstraint);
              Set<String> tmpLtl = new HashSet<String>();tmpLtl.addAll(ifthenAutomataAsText);tmpLtl.add(answerType+" "+addedConstraint);
              if(!config.isUseConstraints())
              {
                Collection<List<Label>> counters = spin.check(ptaHardFacts, tmpLtl).getCounters();
                if (counters.size()>0)
                {
                  String errorMessage = getHardFactsContradictionErrorMessage(tmpLtl, counters);
                  if (obtainedLTLViaAuto) // cannot recover from autosetting, otherwise warn a user
                    throw new IllegalArgumentException(errorMessage);
View Full Code Here

TOP

Related Classes of statechum.analysis.learning.spin.SpinUtil

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.