Commit 11ab1f18 authored by Michele's avatar Michele

added example with learnLib for tictactoe

parent b965fd52
......@@ -30,7 +30,8 @@ class CompleteTicTacToeTester(AbstractTester):
self._teacher = teacher
# upper bound: 9! (possible plays, also invalid ones)
# according to wikipedia
self._all_games = set(itertools.permutations(['0','1','2','3','4','5','6','7','8']))
# Reduced to games of length 5 (maximum number of X in a bard)
self._all_games = set(itertools.permutations(['0','1','2','3','4','5','6','7','8'],5))
self._logger = logger or logging.getLogger(__name__)
# Search a counterexample to teacher ioco model
......
This is the code used for comparing my tool with learnLib version 0.9.1.
I use this version because of some errors introduced in learnLib by newer versions.
LearnLib code, readme, license and other relevent information can be found at https://github.com/LearnLib/learnlib
How to setup this example:
In your favorite IDE create a project including the content of the src folder and adding to the path
the LearnLib library (the content of the lib folder). Everything has been tested in Eclipse Lunawith JavaSE-1.7.
Adapt the paths to your specific case (around line 178 of TicTacToeLearner.java) and run it to
learn the SUT. You might need to install Graphviz for the dot program.
package nl.ru.cs.mvolpato.tictaclearnlib;
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"));
// consume an output
String outputStr=sockin.readLine();
System.out.println("Consuming output in connection: "+outputStr);
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
//System.out.println("Input: "+inputStr);
sockout.println(inputStr);
sockout.flush();
// Receive output from SUT
String outputStr=sockin.readLine();
//System.out.println("Output: "+outputStr);
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() {
try {
// send reset to SUT
//System.out.println("Resetting");
sockout.println("9");
sockout.flush();
// consume an output
String outputStr=sockin.readLine();
//System.out.println("Consuming output: "+outputStr);
} catch (IOException e) {
e.printStackTrace();
}
run=run+1;
}
public void close() {
//try {
sockout.println("EXIT");
sockout.flush();
/*sockin.close();
sockout.close();
sock.close();*/
//} catch (IOException ex) {
//}
}
}
package nl.ru.cs.mvolpato.tictaclearnlib;
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 TicTacToeLearner {
public static int sutInterface_portNumber=29000;
/*
* 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("0");
inputs.add("1");
inputs.add("2");
inputs.add("3");
inputs.add("4");
inputs.add("5");
inputs.add("6");
inputs.add("7");
inputs.add("8");
// 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("0"));
// 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.RIVEST_SCHAPIRE_ALLSUFFIXES, // handling of counterexamples
ClosingStrategies.CLOSE_FIRST // 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
3, // int minDepth
6 // 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,
completeOracle, // 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 = "/home/mic/repo/learnLTS/examples/tictactoe/learnLib/TicTacToe.dot";
PrintStream writer = new PrintStream(
new FileOutputStream(filename));
GraphDOT.write(result, inputs, writer); // may throw IOException!
System.out.println(executeCommand("dot -Tpdf /home/mic/repo/learnLTS/examples/tictactoe/learnLib/TicTacToe.dot -o /home/mic/repo/learnLTS/examples/tictactoe/learnLib/TicTacToe.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();
}
}
......@@ -80,7 +80,7 @@ class TicTacToeTeacher(AbstractTeacher):
# reset SUL
self._socket.sendall(bytes("9", 'UTF-8'))
grid = self._socket.recv(1024).decode("utf-8")
if grid == "012345678":
if grid == "_________":
return True
return False
......
......@@ -395,10 +395,14 @@ if __name__ == "__main__":
#Receiving from client
data = conn.recv(1024)
if not data or str(data.decode("utf-8")) == "EXIT\r\n":
break
move1 = int(data.decode("utf-8"))
move1 = data
if not isinstance(data,int):
if (not data or "EXIT" in str(data.decode("utf-8"))):
break
if isinstance(data.decode("utf-8")[0],int):
move1 = data.decode("utf-8")[0]
else:
move1 = int(data.decode("utf-8")[0])
logger.debug("Received: " + str(move1))
......@@ -423,12 +427,12 @@ if __name__ == "__main__":
if winner != 0:
logger.debug("We have a winner!")
board = board + " END"
conn.sendall(bytes(board, 'UTF-8'))
#board = board + "END"
conn.sendall(bytes(board+"\n", 'UTF-8'))
newGame()
else:
logger.debug("Sending: " + board)
conn.sendall(bytes(board, 'UTF-8'))
conn.sendall(bytes(board+"\n", 'UTF-8'))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment