Skip to content

Commit 7990ef2

Browse files
committed
added README.md & documentation + some cleanups
1 parent 9ef29ee commit 7990ef2

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# learnlib-py4j-example
2+
3+
This example shows how to learn a python-based system under learning (SUL) using [LearnLib][learnlib].
4+
5+
This example is a *python-first* example, meaning the core of our setup is written in Python and we use [Py4J][py4j] in order to use the Java based LearnLib from our Python program.
6+
7+
If you want a *java-first* approach, you may look into technologies such as [Jython][jython] which allows you to run Python programs on the JVM. If you want to go deeper down that rabbit hole, [GraalVM][graal] may be worth a look as well.
8+
9+
10+
## Requirements
11+
12+
In order to run the Java side of the example you need to have a working [JDK][jdk] 8+ installation.
13+
OpenJDK should work just as well as OracleJDK.
14+
Furthermore, we use [Maven][maven] in order to build our LearnLib-Py4J connector.
15+
16+
---
17+
18+
For the Python side of this example you need to have a working [Python][python] installation.
19+
The example has only been tested with Python3 - Python2 may or may not work.
20+
We strongly suggest to install the [`virtualenv`][venv] tool in order setup the Python side of Py4J without affecting your global Python installation - although technically you only need to have the `python-py4j` libraries installed somewhere.
21+
22+
---
23+
24+
In order to show the learned hypothesis automata, we suggest to install [GraphVIZ][graphviz].
25+
However, if GraphVIZ (more specifically, `DOT`) is not installed, LearnLib will fallback to the [JUNG][jung] library, which is a fully Java-based visualization approach.
26+
27+
28+
## Preparing the example
29+
30+
31+
First, we will build the Java side of this example, which will leave us with an executable JAR containing the LearnLib and Py4J code.
32+
33+
```
34+
cd java
35+
mvn package
36+
cd ..
37+
```
38+
39+
---
40+
41+
Then, we setup our virtual python environment and install the py4j libraries
42+
43+
```
44+
virtualenv python/venv
45+
source python/venv/bin/activate
46+
pip install py4j==0.10.8.1
47+
```
48+
49+
## Running the example
50+
51+
To run the example, we first start our JVM process that listens for any calls performed by our Python programm (via the Py4J framework):
52+
53+
`java -jar java/target/learnlib-py4j-example-1.0-SNAPSHOT.jar`
54+
55+
---
56+
57+
Then, we simply run our Python program:
58+
59+
`python python/Main.py`
60+
61+
---
62+
63+
Once we are finished, the JVM process can be terminated by pressing <kbd>Ctrl</kbd> + <kbd>C</kbd>
64+
65+
66+
[learnlib]: https://github.com/LearnLib/learnlib
67+
[py4j]: https://www.py4j.org/
68+
[jython]: http://www.jython.org/
69+
[graal]: https://www.graalvm.org/
70+
[jdk]: https://www.oracle.com/technetwork/java/javase/overview/index.html
71+
[maven]: https://maven.apache.org/
72+
[python]: https://www.python.org/
73+
[venv]: https://virtualenv.pypa.io
74+
[graphviz]: http://www.graphviz.org/
75+
[jung]: http://jung.sourceforge.net/

java/pom.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ limitations under the License.
2727
<properties>
2828
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2929

30-
<!-- AutomataLib requires Java 8 -->
30+
<!-- LearnLib requires Java 8 -->
3131
<maven.compiler.source>1.8</maven.compiler.source>
3232
<maven.compiler.target>1.8</maven.compiler.target>
3333

3434
<!-- Version of LearnLib to use -->
3535
<learnlib.version>0.13.1</learnlib.version>
36+
<py4j.version>0.10.8.1</py4j.version>
37+
<shade-plugin.version>3.2.1</shade-plugin.version>
3638
</properties>
3739

3840
<dependencyManagement>
@@ -57,7 +59,7 @@ limitations under the License.
5759
<dependency>
5860
<groupId>net.sf.py4j</groupId>
5961
<artifactId>py4j</artifactId>
60-
<version>0.10.8.1</version>
62+
<version>${py4j.version}</version>
6163
</dependency>
6264

6365
<!-- provide an SLF4J implementation -->
@@ -73,7 +75,7 @@ limitations under the License.
7375
<plugin>
7476
<groupId>org.apache.maven.plugins</groupId>
7577
<artifactId>maven-shade-plugin</artifactId>
76-
<version>3.2.1</version>
78+
<version>${shade-plugin.version}</version>
7779
<executions>
7880
<execution>
7981
<phase>package</phase>

python/Main.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from py4j.java_gateway import JavaGateway, CallbackServerParameters
22

3-
3+
# This class represents the Python side implementation of our system under learning (SUL)
44
class PySUL:
55

66
def __init__(self, gateway):
@@ -29,26 +29,36 @@ class Java:
2929

3030

3131
def main():
32+
# Create our connection to the JVM process
3233
gateway = JavaGateway(callback_server_parameters=CallbackServerParameters())
3334

35+
# Instantiate our Python SUL and get the learning alphabet
3436
sul = PySUL(gateway)
3537
alphabet = sul.alphabet
3638

39+
# Construct the membership oracle
3740
mq_oracle = gateway.jvm.de.learnlib.oracle.membership.SULOracle(sul)
41+
42+
# Construct the equivalence oracle
3843
eq_oracle = gateway.jvm.de.learnlib.oracle.equivalence.WMethodEQOracle(mq_oracle, 3)
3944

45+
# Construct the learning algorithm (here TTT)
4046
ttt = gateway.jvm.de.learnlib.algorithms.ttt.mealy.TTTLearnerMealyBuilder() \
4147
.withAlphabet(alphabet) \
4248
.withOracle(mq_oracle) \
4349
.create()
4450

51+
# Construct the experiment, that runs the active learning loop until no more counterexamples can be found.
4552
experiment = gateway.jvm.de.learnlib.util.Experiment(ttt, eq_oracle, alphabet)
4653
experiment.run()
4754

55+
# Get the final hypothesis of our SUL
4856
hyp = experiment.getFinalHypothesis()
4957

58+
# Construct a buffer that we will use to print results on the Python side of our setup
5059
string_writer = gateway.jvm.java.io.StringWriter()
5160

61+
# Serialize the hypothesis to the DOT format and write it to the string_writer
5262
gateway.jvm.net.automatalib.serialization.dot.GraphDOT.write(hyp, alphabet, string_writer,
5363
# While varargs allow us to skip this parameter in Java, the method signature expects an array \
5464
gateway.new_array(
@@ -59,12 +69,14 @@ def main():
5969
print()
6070
print(string_writer.toString())
6171

72+
# Visualize the hypothesis
6273
gateway.jvm.net.automatalib.visualization.Visualization.visualize(hyp, alphabet,
6374
# While varargs allow us to skip this parameter in Java, the method signature expects an array \
6475
gateway.new_array(
6576
gateway.jvm.net.automatalib.visualization.VisualizationHelper,
6677
0))
6778

79+
# Close our connection
6880
gateway.close()
6981

7082

0 commit comments

Comments
 (0)