Package statechum.analysis.learning

Source Code of statechum.analysis.learning.RPNILearner

/* Copyright (c) 2006, 2007, 2008 Neil Walkinshaw and Kirill Bogdanov
*
* This file is part of StateChum
*
* StateChum is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* StateChum is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with StateChum.  If not, see <http://www.gnu.org/licenses/>.
*/
package statechum.analysis.learning;

import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import statechum.Configuration;
import statechum.Pair;
import statechum.StringLabel;
import statechum.analysis.learning.Learner;
import statechum.analysis.learning.rpnicore.LearnerGraph;
import statechum.analysis.learning.rpnicore.PathRoutines;
import statechum.analysis.learning.rpnicore.Transform.ConvertALabel;
import statechum.model.testset.PTASequenceEngine;


import statechum.DeterministicDirectedSparseGraph.CmpVertex;
import statechum.Label;
import statechum.Trace;
import statechum.analysis.Erlang.ErlangLabel;
import statechum.analysis.Erlang.OTPBehaviour;

public abstract class RPNILearner extends Observable implements Learner {

    final protected Configuration config;
    /** The frame in relation to which to pop dialog boxes. */
    protected Frame parentFrame;

    protected final ConvertALabel labelConverter;
   
    @Override
  public ConvertALabel getLabelConverter()
    {
      return labelConverter;
    }
   
    public RPNILearner(Frame parent, Configuration c, ConvertALabel conv) {
        config = c;
        parentFrame = parent;
        labelConverter = conv;
    }

   
   
    /** Retrieves the configuration used by this learner. */
    public Configuration getConfig() {
        return config;
    }

    /** Initialises this learner. */
    abstract
    @Override
    public LearnerGraph init(Collection<List<Label>> plus, Collection<List<Label>> minus);

    /** Initialises this learner. */
    abstract
    @Override
    public LearnerGraph init(PTASequenceEngine en, int plus, int minus);

    public
    @Override
    LearnerGraph learnMachine(PTASequenceEngine en, int plusSize, int minusSize) {
      topLevelListener.init(en, plusSize, minusSize);
        return learnMachine();
    }

    public
    @Override
    LearnerGraph learnMachine(Collection<List<Label>> plus, Collection<List<Label>> minus) {
        topLevelListener.init(plus, minus);
        return learnMachine();
    }
    protected Learner topLevelListener = this;

    /** Sets the highest listener to receive notification calls;
     * it is expected that listeners will propagate calls down the chain
     * so that this learner eventually gets to execute its own methods.
     *
     * @param top new top of the stack of listeners.
     */
    public
    @Override
    void setTopLevelListener(Learner top) {
        topLevelListener = top;
    }

    /** Given a score, we need to determine whether to ask questions. This depends on a number
     * of configuration parameters.
     *
     * @param score score we are looking at
     * @return whether any questions should be asked or we could just proceed with merging.
     */
    protected boolean shouldAskQuestions(long score) {
        if (!config.getAskQuestions()) {
            return false;
        }

        if (config.getCertaintyThreshold() >= 0 && score > config.getCertaintyThreshold()) {
            return false;
        }

        if (score < config.getMinCertaintyThreshold()) {
            return false;
        }

        return true;
    }

    /** Pretty-prints a supplied question. Useful for questions with Erlang labels which
     * contain functions they are associated with.
     */
    public static String questionToString(List<? extends Label> question)
    {
    StringBuffer questionString = new StringBuffer();questionString.append('[');
    boolean first = true;
    for(Label lbl:question)
    {
      if (!first) questionString.append(',');else first = false;
      if (lbl instanceof StringLabel)
        questionString.append(lbl.toErlangTerm());
      else
        if (lbl instanceof ErlangLabel)
          questionString.append(OTPBehaviour.convertModToErl(lbl).toErlangTerm());
        else
          throw new IllegalArgumentException("unknown type of label "+lbl.getClass());
    }
    questionString.append(']');
    return questionString.toString();
    }
   
    int count = 1;
    public int getCount()
    {
      return count;
    }

    /** Updates listeners only if this object has been modified and debug mode is on, by calling
     * <pre>
     * setChanged()
     * </pre>
     * @param g the graph to display in the associated view
     * @param hardFacts the graph from which the current one was built
     */
    public void updateGraph(LearnerGraph g, LearnerGraph hardFacts) {
        setChanged();/*
        System.out.println("stage "+count);
        if (count ++ % 15 == 0 && config.getAskQuestions())
        {
          Configuration lConf = config.copy();lConf.setDebugMode(false);lConf.setAskQuestions(false);
          RPNIUniversalLearner tmpLearner = new RPNIUniversalLearner(parentFrame, lConf, getLabelConverter());
          LearnerGraph gCopy = new LearnerGraph(g,lConf);
          tmpLearner.setTentativeAutomaton(gCopy);
          //Visualiser.updateFrame(tmpLearner.learnMachine(), null);
          notifyObservers(tmpLearner.learnMachine());
          Visualiser.waitForKey();         
        }*/
        /*
        if (config.getDebugMode()) {
            Map<VertID, Collection<VertID>> mergedToHard = g.getCache().getMergedToHardFacts();
            if (hardFacts != null && mergedToHard != null) {
                Map<CmpVertex, List<Label>> vertToPath = hardFacts.pathroutines.computeShortPathsToAllStates();
                Map<CmpVertex,CachedData.ErlangCoverageData> vertexToCoverage = new TreeMap<CmpVertex,CachedData.ErlangCoverageData>();
                for(CmpVertex v:g.transitionMatrix.keySet())
                {
                  CachedData.ErlangCoverageData erlCoverage = new CachedData.ErlangCoverageData();
                  erlCoverage.coverage = new LinkedList<CodeCoverageMap>();
                    Collection<Trace> allPrefixTraces = new LinkedList<Trace>();
                    Collection<VertID> verticesInHardFacts=mergedToHard.get(v);
                    if (verticesInHardFacts != null)
                    {
                        for (VertID hard : verticesInHardFacts) {
                            Trace path = new Trace(vertToPath.get(hardFacts.findVertex(hard)));
                            allPrefixTraces.add(path);

                            // Walk the hardFacts from here to determine all possible paths from this state, then determine their code coverage
                            CmpVertex hardv = hardFacts.findVertex(hard);
                            Collection<Trace> paths = getPaths(path, hardv, hardFacts);
                            for (Trace p : paths) {
                                //System.out.println("Generating coverage for " + path + "-" + p);
                                Collection<Trace> onlyPath = new LinkedList<Trace>();
                                onlyPath.add(p);
                                Pair<Trace, Trace> prefixSuffix = ErlangOracleVisualiser.getPrefixSuffixPair(allPrefixTraces, onlyPath);
                                CodeCoverageMap map = ErlangOracleVisualiser.getCoverageMap(prefixSuffix.firstElem, prefixSuffix.secondElem);
                                //System.out.println("Generated coverage " + prefixSuffix[0] + "-" + prefixSuffix[1] + ": " + map.toString());
                                erlCoverage.coverage.add(map);
                            }
                        }
                    }
                   
                    vertexToCoverage.put(v, erlCoverage);
                }
                g.getCache().setErlangCoverage(vertexToCoverage);
            }
          notifyObservers(g);
          //JOptionPane.showMessageDialog(parentFrame, "Eggs are not supposed to be green.");
        }
        */
    }
   
    /* This one is actually a specialised version of computeShortPathsToAllStates()
     */
    protected Collection<Trace> getPaths(Trace prefix, CmpVertex v, LearnerGraph hardFacts) {
        Collection<Trace> result = new LinkedList<Trace>();

        Map<Label, CmpVertex> edges = hardFacts.getTransitionMatrix().get(v);
        if (edges.isEmpty()) {
            result.add(prefix);
        } else {
            for (Map.Entry<Label, CmpVertex> e : edges.entrySet()) {
                Trace newPath = prefix.clone();
                newPath.add(e.getKey());
                result.addAll(getPaths(newPath, e.getValue(), hardFacts));
            }
        }

        return result;
    }
   
    final String questionPrefix = "";

    protected List<String> beautifyQuestionList(List<Label> question) {
        List<String> questionList = new LinkedList<String>();
        int i = 0;
        for (Label q : question) {
            questionList.add(questionPrefix + "(" + i++ + ") " + q);
        }

        return questionList;
    }
    /** The dialog to be displayed to a user with questions to select.
     * This field should not really be public, but since different packages refer to it,
     * I chose to make it public for the time being.
     */
    public JDialog dialog = null;
    /** the option pane. */
    protected JOptionPane jop = null;

    /** Cancels a dialog, if present. With no dialog, learner thread will terminate within a reasonable amount of time.
     */
    public void terminateUserDialogueFrame() {
        assert (SwingUtilities.isEventDispatchThread());
        if (dialog != null && jop != null && dialog.isVisible()) {
            jop.setValue(new Integer(
                    JOptionPane.CLOSED_OPTION));// from http://java.sun.com/docs/books/tutorial/uiswing/components/examples/CustomDialog.java    }
        }    // The setting of the option above corresponds to hitting "close" or "ESC" on the dialogue,
        // which is interpreted by the learner as a request to terminate learning, hence
        // the learner stops and the corresponding thread terminates. For this reason,
        // it is appropriate to issue a .join() on the learner thread.
    }
    public final static String QUESTION_AUTO = "<auto>";
    public final static String QUESTION_SPIN = "<spin>";
    public final static String QUESTION_USER = "<USER>";
    public final static String QUESTION_IGNORE = "<ignore>";
    public final static String QUESTION_INCOMPATIBLE = "<incompatible>";
    public final static String QUESTION_NEWTRACE = "<newtrace>";
   
    @Override
    public void Restart(@SuppressWarnings("unused") RestartLearningEnum mode) {// this method is used to let observers know what is going on, the actual restarts are handled by the main learner routine.
    }

    /** Where we expect a specific value in order to proceed without a restart, the answer is
     * highlighted in the user-displayed dialog box.
     *
     * @param str string to augment
     * @return resulting value
     */
    static String addAnnotationExpected(String str) {
        if (str.length() < 1) {
            return str;
        }

        return "<html>" + str + " <font color=blue>&nbsp;&larr;";
    }

    /** Displays a tentative graph and asks user a supplied question.
     * Options are to be shown as choices in addition to yes/element_not_accepted.
     */
    @Override
    public Pair<Integer,String> CheckWithEndUser(@SuppressWarnings("unused") LearnerGraph model,
        final List<Label> question,
        final int expectedForNoRestart,
            final List<Boolean> consistentFacts,
            @SuppressWarnings("unused") final PairScore pairBeingMerged,
            final Object[] moreOptions)
    {
        final List<String> questionList = beautifyQuestionList(question);
        final AtomicInteger answer = new AtomicInteger(AbstractOracle.USER_WAITINGFORSELECTION);
        Integer outcome = PathRoutines.identifyTheOnlyChoice(consistentFacts);
        if (outcome != null) {
            answer.getAndSet(outcome);
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {

                    public
                    @Override
                    void run() {
                        final Object[] options = new Object[1 + moreOptions.length];

                        // A click on an element means a reject for that element and accept to all
                        // earlier elements, hence we have to disable all those which should not
                        // be rejected. The fact that we do only consider prefix-closed questions
                        // implies that a whole prefix will be accept-only.
                        Iterator<String> inputIter = questionList.iterator();
                        Iterator<Boolean> factsIter = consistentFacts == null ? null : consistentFacts.iterator();
                        List<String> listElements = new ArrayList<String>(questionList.size());
                        int inputCounter = 0;
                        while (inputIter.hasNext()) {
                            String currentElement = inputIter.next();
                            Boolean fact = factsIter == null ? null : factsIter.next();
                            String elementHtml = null;
                            if (fact != null && fact.booleanValue()) {
                                elementHtml = "<html><font color=gray>" + currentElement;
                            } else {
                                elementHtml = "<html><font color=green>" + currentElement;
                            }

                            if (inputCounter == expectedForNoRestart) {
                                elementHtml = addAnnotationExpected(elementHtml);
                            }
                            ++inputCounter;
                            listElements.add(elementHtml);
                        }
                        @SuppressWarnings({ "unchecked", "rawtypes" })
            final JList javaList = new JList(listElements.toArray());
                        String optionZero = null;
                        Boolean lastFact = consistentFacts.get(consistentFacts.size() - 1);
                        if (lastFact != null && !lastFact.booleanValue()) // last element has to be a reject
                        {
                            optionZero = "<html><font color=grey>cannot accept";
                        } else {
                            optionZero = "<html><font color=green>Accept";
                        }

                        if (expectedForNoRestart == AbstractOracle.USER_ACCEPTED) {
                            optionZero = addAnnotationExpected(optionZero);
                            assert lastFact == null || lastFact.booleanValue();
                        }
                        options[0] = optionZero;
                        System.arraycopy(moreOptions, 0, options, 1, moreOptions.length);
                        final JLabel label = new JLabel("<html><font color=red>Click on the first non-accepting element below", SwingConstants.CENTER);
                        jop = new JOptionPane(new Object[]{label, javaList},
                                JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[0]);
                        dialog = new JDialog(parentFrame, "Valid input string?", false);
                        dialog.setContentPane(jop);

                        // the following chunk is partly from http://java.sun.com/docs/books/tutorial/uiswing/components/dialog.html
                        dialog.setDefaultCloseOperation(
                                WindowConstants.DO_NOTHING_ON_CLOSE);
                        dialog.addWindowListener(new WindowAdapter() {

                            @Override
                            public void windowClosing(@SuppressWarnings("unused") WindowEvent we) {
                                jop.setValue(new Integer(
                                        JOptionPane.CLOSED_OPTION));// from http://java.sun.com/docs/books/tutorial/uiswing/components/examples/CustomDialog.java
                            }
                        });
                        jop.addPropertyChangeListener(new PropertyChangeListener() {

                            public
                            @Override
                            void propertyChange(PropertyChangeEvent e) {
                                String prop = e.getPropertyName();

                                Object value = e.getNewValue();

                                if (dialog.isVisible() && e.getSource() == jop
                                        && (prop.equals(JOptionPane.VALUE_PROPERTY))) {
                                    boolean clickValid = true;
                                    int i = 0;
                                    for (; i < options.length && options[i] != value; ++i)
                                    {}
                                    if (i == options.length) {
                                        i = AbstractOracle.USER_CANCELLED;// nothing was chosen
                                    } else {
                                        if (i == 0) {
                                            Boolean fact = consistentFacts.get(consistentFacts.size() - 1);
                                            clickValid = (fact == null || fact.booleanValue());
                                        }
                                        i = AbstractOracle.USER_ACCEPTED - i; // to ensure that zero translates into USER_ACCEPTED and other choices into lower numbers
                                    }

                                    if (clickValid) {
                                        // one of the valid choices was made, record which one and close the window
                                        answer.getAndSet(i);
                                        synchronized (answer) {
                                            answer.notifyAll();
                                        }

                                        dialog.setVisible(false);
                                        dialog.dispose();
                                    }
                                }
                            }
                        });
                        javaList.addListSelectionListener(new ListSelectionListener() {

                            public
                            @Override
                            void valueChanged(ListSelectionEvent e) {
                                if (dialog.isVisible() && e.getSource() == javaList
                                        && !e.getValueIsAdjusting() && !javaList.isSelectionEmpty()) {
                                    int position = javaList.getLeadSelectionIndex();
                                    Boolean fact = consistentFacts.get(position);
                                    if (fact == null || !fact.booleanValue()) {
                                        answer.getAndSet(position);
                                        synchronized (answer) {
                                            answer.notifyAll();
                                        }

                                        dialog.setVisible(false);
                                        dialog.dispose();
                                    }
                                }
                            }
                        });
                        dialog.pack();
                        //rejectElements.setListData(questionList.toArray());
                        dialog.setVisible(true);
                    }
                });
                synchronized (answer) {
                    while (answer.get() == AbstractOracle.USER_WAITINGFORSELECTION) {
                        answer.wait();// wait for a user to make a response
                    }
                }
            } catch (InvocationTargetException e) {
                //e.printStackTrace();
                // if we cannot make a call, return a negative number - nothing do not know what else to do about it.
            } catch (InterruptedException e) {
                // if we are interrupted, return a negative number - nothing do not know what else to do about it.
            }
        }
        if (answer.get() == AbstractOracle.USER_WAITINGFORSELECTION) // this one if an exception was thrown
        {
            answer.getAndSet(AbstractOracle.USER_CANCELLED);
        }
        return new Pair<Integer, String>(answer.get(), null);
    }
}
TOP

Related Classes of statechum.analysis.learning.RPNILearner

TOP
Copyright © 2018 www.massapi.com. 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.