--- /dev/null
+package nl.ru.cs.TT1415.assignment3;
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import net.automatalib.automata.transout.MealyMachine;
+import net.automatalib.util.graphs.dot.GraphDOT;
+import net.automatalib.words.Alphabet;
+import net.automatalib.words.Word;
+import net.automatalib.words.impl.SimpleAlphabet;
+import de.learnlib.algorithms.lstargeneric.ce.ObservationTableCEXHandlers;
+import de.learnlib.algorithms.lstargeneric.closing.ClosingStrategies;
+import de.learnlib.algorithms.lstargeneric.mealy.ExtensibleLStarMealy;
+import de.learnlib.api.LearningAlgorithm.MealyLearner;
+import de.learnlib.api.SUL;
+import de.learnlib.cache.Caches;
+import de.learnlib.eqtests.basic.CompleteExplorationEQOracle;
+import de.learnlib.eqtests.basic.RandomWordsEQOracle;
+import de.learnlib.eqtests.basic.WMethodEQOracle.MealyWMethodEQOracle;
+import de.learnlib.experiments.Experiment.MealyExperiment;
+import de.learnlib.oracles.ResetCounterSUL;
+import de.learnlib.oracles.SULOracle;
+import de.learnlib.statistics.SimpleProfiler;
+import de.learnlib.statistics.StatisticSUL;
+
+
+public class CandyLearner {
+
+ public static int sutInterface_portNumber=7892;
+
+ /*
+ * The Adapter: needed in order to let LearnLib and the sut to communicate
+ *
+ */
+ public static class SULAdapter implements SUL<String, String> {
+
+ // system under learning
+ private SutSocketWrapper sul = new SutSocketWrapper(sutInterface_portNumber);
+
+ // reset the SUL
+ @Override
+ public void reset() {
+ sul.sendReset();
+ }
+
+ // execute one input on the SUL
+ @Override
+ public String step(String in) {
+ String output = sul.sendInput(in);
+ //System.out.println(in + ":" + output);
+ return output;
+ }
+ }
+
+ public static void main(String[] args) throws NoSuchMethodException, IOException {
+
+ // create alphabet
+ Alphabet<String> inputs = new SimpleAlphabet<>();
+ inputs.add("IREFUND");
+ inputs.add("IBUTTONMARS");
+ inputs.add("IBUTTONSNICKERS");
+ inputs.add("IBUTTONBOUNTY");
+ inputs.add("ICOIN10");
+ inputs.add("ICOIN5");
+
+ // Instantiate the sut
+ SUL<String,String> sul = new SULAdapter();
+
+ // oracle for counting queries wraps sul
+ StatisticSUL<String, String> statisticSul = new ResetCounterSUL<>("membership queries", sul);
+
+ SUL<String,String> effectiveSul = statisticSul;
+ // use caching in order to avoid duplicate queries
+ effectiveSul = Caches.createSULCache(inputs, effectiveSul);
+
+ SULOracle<String, String> mqOracle = new SULOracle<>(effectiveSul);
+
+ // create initial set of suffixes
+ List<Word<String>> suffixes = new ArrayList<>();
+ suffixes.add(Word.fromSymbols("IREFUND"));
+ suffixes.add(Word.fromSymbols("IBUTTONMARS"));
+ suffixes.add(Word.fromSymbols("IBUTTONSNICKERS"));
+ suffixes.add(Word.fromSymbols("IBUTTONBOUNTY"));
+ suffixes.add(Word.fromSymbols("ICOIN10"));
+ suffixes.add(Word.fromSymbols("ICOIN5"));
+
+ // construct L* instance (almost classic Mealy version)
+ // almost: we use words (Word<String>) in cells of the table
+ // instead of single outputs.
+ MealyLearner<String,String> lstar =
+ new ExtensibleLStarMealy<>(
+ inputs, // input alphabet
+ mqOracle, // mq oracle
+ suffixes, // initial suffixes
+ ObservationTableCEXHandlers.FIND_LINEAR_ALLSUFFIXES, // handling of counterexamples
+ ClosingStrategies.CLOSE_SHORTEST // choose row for closing the table
+ );
+
+ // create random words equivalence test
+ RandomWordsEQOracle<String, Word<String>, MealyMachine<?,String,?,String>> randomWords =
+ new RandomWordsEQOracle<String, Word<String>, MealyMachine<?,String,?,String>>(
+ mqOracle,
+ 3, // int minLength
+ 8, // int maxLength
+ 1000, // int maxTests
+ new Random(46346293) // make results reproducible
+ );
+
+ // create complete exploration equivalence test
+ CompleteExplorationEQOracle<String, Word<String>> completeOracle =
+ new CompleteExplorationEQOracle<>(
+ mqOracle, // a membership oracle
+ 5, // int minDepth
+ 7 // int maxDepth
+ );
+
+ // create equivalence oracle based on the W method
+ MealyWMethodEQOracle<String, String> wOracle=
+ new MealyWMethodEQOracle<>(
+ 5, //int maxDepth
+ mqOracle // a membership oracle
+ );
+
+
+ // construct a learning experiment from
+ // the learning algorithm and one of the equivalence oracles.
+ // The experiment will execute the main loop of
+ // active learning
+ MealyExperiment<String,String> experiment =
+ new MealyExperiment<>(
+ lstar,
+ randomWords, // equivalence oracle, choose among [randomWords | completeOracle | wOracle] **remember to change their settings**
+ inputs // input alphabet
+ );
+
+ // turn off time profiling
+ experiment.setProfile(true);
+
+ // enable logging of models
+ experiment.setLogModels(true);
+
+ // run experiment
+ experiment.run();
+
+ // get learned model
+ MealyMachine<?, String, ?, String> result = experiment.getFinalHypothesis();
+
+ // report results
+ System.out.println("-------------------------------------------------------");
+
+ // profiling
+ System.out.println(SimpleProfiler.getResults());
+
+ // learning statistics
+ System.out.println(experiment.getRounds().getSummary());
+ System.out.println(statisticSul.getStatisticalData().getSummary());
+
+ // model statistics
+ System.out.println("States: " + result.size());
+ System.out.println("Sigma: " + inputs.size());
+
+ // show model
+ System.out.println();
+ System.out.println("Model: ");
+
+ GraphDOT.write(result, inputs, System.out); // may throw IOException!
+// Writer w = DOT.createDotWriter(true);
+// GraphDOT.write(result, inputs, w);
+// w.close();
+
+ String filename = "/path/to/yourfolder/CandyMachine.dot";
+ PrintStream writer = new PrintStream(
+ new FileOutputStream(filename));
+ GraphDOT.write(result, inputs, writer); // may throw IOException!
+
+ System.out.println(executeCommand("dot -Tpdf /path/to/yourfolder/CandyMachine.dot -o /path/to/yourfolder/CandyMachine.pdf"));
+
+
+ System.out.println("-------------------------------------------------------");
+
+ }
+
+ // execute command, for translation from dot to pdf
+ public static String executeCommand(String command) {
+
+ StringBuffer output = new StringBuffer();
+
+ Process p;
+ try {
+ p = Runtime.getRuntime().exec(command);
+ p.waitFor();
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(p.getInputStream()));
+
+ String line = "";
+ while ((line = reader.readLine())!= null) {
+ output.append(line + "\n");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return output.toString();
+
+ }
+}
--- /dev/null
+package nl.ru.cs.TT1415.assignment3;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+
+public class SutSocketWrapper {
+ private Socket sock;
+ private PrintWriter sockout;
+ private BufferedReader sockin;
+ private int run;
+
+ public SutSocketWrapper(int portNumber) {
+
+ try {
+ sock = new Socket("localhost", portNumber);
+
+ /* Call setTcpNoDelay to improve communication performance : */
+
+ sock.setTcpNoDelay(true); // remove unnecessary delay in socket communication!
+
+
+ // make char writer from byte writer which automatically encodes chars using UTF-8 and
+ // automatically flushes the buffer on each println call.
+ sockout = new PrintWriter(new OutputStreamWriter(sock.getOutputStream(), "UTF-8"),true);
+ // make char reader from byte reader which automatically decodes bytes to chars using UTF-8
+ sockin = new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8"));
+
+
+ run=1;
+ } catch (IOException e) {
+ // e.printStackTrace();
+ System.err.println("");
+ System.err.println("\n\nPROBLEM: problem connecting with SUT:\n\n " + e.getMessage() +"\n\n");
+ System.exit(1);
+ }
+ }
+
+
+
+ public String sendInput(String inputStr) {
+ try {
+
+ // Send input to SUT
+ sockout.println(inputStr);
+ sockout.flush();
+
+ // Receive output from SUT
+ String outputStr=sockin.readLine();
+ if (outputStr==null) {
+ System.err.println("");
+ System.err.println("\n\nPROBLEM: problem reading output from SUT: SUT closed connection\n\n " );
+ System.exit(1);
+ }
+
+ return outputStr;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public void sendReset() {
+
+ // send reset to SUT
+ sockout.println("reset");
+ sockout.flush();
+
+ run=run+1;
+ }
+
+
+
+
+ public void close() {
+ /*
+ try {
+ sockin.close();
+ sockout.close();
+ sock.close();
+ } catch (IOException ex) {
+
+ }
+ */
+ }
+
+
+
+}
--- /dev/null
+#!/usr/bin/env python\r
+"""\r
+generates aut for jtorx from dot file learned with learnlib\r
+ '?COIN_1_1'\r
+ '!TEA_0_1'\r
+\r
+note: dot file uses I for input instead of ? and O for output instead of !\r
+"""\r
+# Author: Harco Kuppens\r
+\r
+\r
+import sys, re, pprint # modules from standard lib (python 2.6 and later)\r
+\r
+\r
+\r
+def get_lts_from_dotfile(dot_file):\r
+ """ Get labeled transition system from graphviz dot file\r
+\r
+ The dot file:\r
+ - describes a digraph with labels\r
+ - encodes the start state with the color='red' attribute\r
+ note: this corresponds with the highlighted state in learnlib API\r
+\r
+ Returns: [start_state,transions]\r
+ Where :\r
+ - start_state: start state label\r
+ - transitions: list of transitions\r
+\r
+ """\r
+\r
+ start_state='unknown'\r
+ f=file(dot_file)\r
+ lines=f.readlines()\r
+ \r
+ \r
+\r
+ # find start state \r
+ # line in dot: __start0 -> s0;\r
+ for line in lines:\r
+ if line.find('->') != -1:\r
+ if line.find('__start') != -1:\r
+ start_state=line[line.find('->')+2:].strip(" ;\t\n")\r
+ break\r
+\r
+\r
+ # get transitions\r
+ # line in dot: s5 -> s5 [label="ARTREG 20013226 / 531"];\r
+ transitions=[]\r
+ for line in lines:\r
+ if line.find('__start') != -1:\r
+ continue\r
+ if line.find('->') != -1:\r
+ transitions.append(line)\r
+\r
+ # throw away transitions with the keywords : quiescence or inconsistency or undefined\r
+ #transitions = [ t for t in transitions if ( 'quiescence' not in t ) and ( 'inconsistency' not in t ) and ( 'undefined' not in t )]\r
+\r
+ trans_out=[]\r
+ regexpr_transition=re.compile(r'\s*(\w*)\s*-\>\s*(\w*)\s*\[label=\"(.*)\"\]')\r
+ regexpr_tag=re.compile(r'<[^>]+>')\r
+ for transition in transitions:\r
+ match=regexpr_transition.match(transition)\r
+ if match:\r
+ match=match.groups()\r
+ label=regexpr_tag.sub('',match[2])\r
+ trans_out.append({\r
+ 'source' : match[0],\r
+ 'target' : match[1],\r
+ 'label': label\r
+ })\r
+\r
+ states=set()\r
+ for t in trans_out:\r
+ states.add(t['source'])\r
+ states.add(t['target'])\r
+\r
+\r
+ return [start_state,states,trans_out]\r
+\r
+\r
+def parse_labels_of_mealy_lts(transitions):\r
+ """Parse labels of labeled transition system\r
+ """\r
+ trans_out=[]\r
+ for t in transitions:\r
+ label=t['label']\r
+ [inputstr,outputstr]=label.split('/')\r
+ trans_out.append({\r
+ 'source' : t['source'],\r
+ 'target' : t['target'],\r
+ 'input': inputstr,\r
+ 'output': outputstr,\r
+ })\r
+ return trans_out\r
+\r
+def split_io_transitions_in_separate_input_and_output_transition(io_transitions,nr_states):\r
+ """Split transitions with both an input and output event into two transitions\r
+\r
+ Makes two sequential transitions with a dummy state in between:\r
+ - dummy state <midstate> is labeled :\r
+ m_<counter>\r
+ - first transition :\r
+ <source> -> <midstate> for <input>\r
+ - second transition :\r
+ <midstate> -> <target> for <output>\r
+ """\r
+ trans_out=[]\r
+ id=nr_states\r
+ for t in io_transitions:\r
+ midstate= 'm' + str(id)\r
+ trans_out.append({\r
+ 'source': t['source'],\r
+ 'target': midstate,\r
+ 'label' : "?" + t['input'].strip(),\r
+ })\r
+ trans_out.append({\r
+ 'source': midstate,\r
+ 'target': t['target'],\r
+ 'label' : "!" + t['output'].strip(),\r
+ })\r
+ id=id+1\r
+\r
+ states=set()\r
+ for t in trans_out:\r
+ states.add(t['source'])\r
+ states.add(t['target'])\r
+\r
+ return [states,trans_out]\r
+\r
+\r
+def transitions2aut(transitions,first_state,nr_of_states):\r
+ nr_of_transitions=len(transitions)\r
+ strings=[ "des(" + first_state[1:] + "," + str(nr_of_transitions) + "," + str(nr_of_states) +")"]\r
+ for t in transitions:\r
+ #aut_edge ::= "(" start_state "," label "," end_state ")"\r
+ strings.append("("+t['source'][1:] + "," + '"' + t['label'] + '"' + "," + t['target'][1:] + ")" )\r
+\r
+ return "\n".join(strings)\r
+\r
+\r
+def dot2aut(dot_filename_in):\r
+ """\r
+ from mealy machine in a .dot file written by DotUtil.write of learnlib\r
+ we create an .aut file containing an lts where input and output each\r
+ have its own labeled transition. An input transition has a\r
+ label starting with '?' and an output transition has a label\r
+ starting with '!'\r
+\r
+ """\r
+\r
+ if dot_filename_in[-4:].lower() != '.dot':\r
+ print "Problem: file '"+ dot_filename_in + "' is not a dot file!!"\r
+ print "Exit!"\r
+ sys.exit(1)\r
+\r
+\r
+ [start_state,states,transitions]=get_lts_from_dotfile(dot_filename_in)\r
+ \r
+\r
+ \r
+ io_transitions=parse_labels_of_mealy_lts(transitions) # each transition has input and output\r
+ [states,transitions]=split_io_transitions_in_separate_input_and_output_transition(io_transitions,len(states)) # each transition only has label again\r
+\r
+ #pprint.pprint(start_state)\r
+ #pprint.pprint(states)\r
+ #pprint.pprint(transitions)\r
+\r
+ result=transitions2aut(transitions,start_state,len(states))\r
+\r
+ aut_filename=dot_filename_in[:-4] + ".aut"\r
+\r
+ f=open(aut_filename ,'w')\r
+ f.write(result)\r
+ f.close()\r
+\r
+ print "written file : " + aut_filename\r
+\r
+\r
+if __name__ == "__main__":\r
+ dot2aut(*sys.argv[1:])\r
+\r