From b7bfa772e82a2a9e2d45e46c91f5fe623679d9bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Euzenat?= <Jerome.Euzenat@inria.fr>
Date: Sun, 4 Apr 2010 09:46:25 +0000
Subject: [PATCH] - cleaned up all tutorial4 for better working with Pellet 2.1

---
 html/tutorial/tutorial4/MyApp.java           |  29 +--
 html/tutorial/tutorial4/Skeleton.java        |  44 ++--
 html/tutorial/tutorial4/index.html           | 215 ++++++++++---------
 html/tutorial/tutorial4/results/myresult.owl |  45 ++++
 4 files changed, 205 insertions(+), 128 deletions(-)
 create mode 100644 html/tutorial/tutorial4/results/myresult.owl

diff --git a/html/tutorial/tutorial4/MyApp.java b/html/tutorial/tutorial4/MyApp.java
index ae4b6442..18425664 100644
--- a/html/tutorial/tutorial4/MyApp.java
+++ b/html/tutorial/tutorial4/MyApp.java
@@ -130,7 +130,7 @@ public class MyApp {
     }
 
     public void run( String[] args ) {
-	String myId = "JETest";
+	String myId = "Test";
 	Alignment al = null;
 	URI uri1 = null;
 	URI uri2 = null;
@@ -166,7 +166,7 @@ public class MyApp {
 	    found = getFromURLString( RESTServ+"retrieve?method=fr.inrialpes.exmo.align.impl.renderer.RDFRendererVisitor&id="+alid, false );
 	    alset = extractFromResult( found, "//retrieveResponse/result/*[1]",true );
 
-	    // This code is heavy as hell
+	    // This code is heavy
 	    String xmlString = null;
 	    try {
 		// Set up the output transformer
@@ -186,7 +186,6 @@ public class MyApp {
 	    }
 
 	    // parse it as an alignment
-	    // (better passing to the SAXHandler)
 	    try {
 		AlignmentParser aparser = new AlignmentParser(0);
 		Alignment alu = aparser.parseString( xmlString );
@@ -243,17 +242,16 @@ public class MyApp {
 
 	// (Sol2) import the data from one ontology into the other
 
-	// ***** Third exercise: querying/reasoning *****
+	// ***** Third exercise: querying and reasoning *****
 
 	// (Sol1) Use SPARQL to answer queries (at the data level)
 	InputStream in = null;
 	QueryExecution qe = null;
 	try {
-	        in = new FileInputStream( merged );
-		//in = new URL("http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl").openStream();
-		//OntModelSpec.OWL_MEM_RDFS_INF or no arguments to see the difference...
-		Model model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF,null);
-	    model.read(in,"file:results/myresult.owl"); 
+	    in = new FileInputStream( merged );
+	    //OntModelSpec.OWL_MEM_RDFS_INF or no arguments to see the difference...
+	    Model model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF,null);
+	    model.read( in, "file:"+tempOntoFileName );
 	    in.close();
 	
 	    // Create a new query
@@ -289,16 +287,10 @@ public class MyApp {
 	    if ( qe != null ) qe.close();
 	}
 
-	// Alternative: Use Pellet to answer queries
-
-	// ***** Fourth exercise: reasoning *****
-
-	// Variant 1: reasoning with merged ontologies
+	// (Sol2) Use Pellet to answer queries (at the ontology level)
 	OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
-	//Pellet
 	OWLReasoner reasoner = null;
 
-	//System.setErr( new PrintStream( new NullStream() ) );
 	// Load the ontology 
 	try {
 	    OWLOntology ontology = manager.loadOntology( IRI.create( "file:"+tempOntoFileName ) );
@@ -318,7 +310,7 @@ public class MyApp {
 	testPelletSubClass( manager, reasoner, estud, person );
 	testPelletSubClass( manager, reasoner, estud, student );
 
-	// Variant 2: reasoning with distributed semantics (IDDL)
+	// (Sol3) reasoning with distributed semantics (IDDL)
 	// test consistency of aligned ontologies
 	IDDLReasoner dreasoner = new IDDLReasoner( Semantics.DL );
 	dreasoner.addOntology( uri1 );
@@ -339,8 +331,7 @@ public class MyApp {
 
     public void testPelletSubClass( OWLOntologyManager manager, OWLReasoner reasoner, OWLClassExpression d1, OWLClassExpression d2 ) {
 	OWLAxiom axiom = manager.getOWLDataFactory().getOWLSubClassOfAxiom( d1, d2 );
-	boolean isit = reasoner.isEntailed( axiom );
-	if ( isit ) {
+	if ( reasoner.isEntailed( axiom ) ) {
 	    System.out.println( "Pellet(Merged): "+clname(d1)+" is subclass of "+clname(d2) );
 	} else {
 	    System.out.println( "Pellet(Merged): "+clname(d1)+" is not necessarily subclass of "+clname(d2) );
diff --git a/html/tutorial/tutorial4/Skeleton.java b/html/tutorial/tutorial4/Skeleton.java
index 4c66081a..244e016b 100644
--- a/html/tutorial/tutorial4/Skeleton.java
+++ b/html/tutorial/tutorial4/Skeleton.java
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) INRIA, 2009
+ * Copyright (C) INRIA, 2009-2010
  *
  * Modifications to the initial code base are copyright of their
  * respective authors, or their employers as appropriate.  Authorship
@@ -29,7 +29,6 @@ import org.semanticweb.owl.align.Alignment;
 import org.semanticweb.owl.align.AlignmentException;
 import org.semanticweb.owl.align.AlignmentProcess;
 import org.semanticweb.owl.align.AlignmentVisitor;
-import org.semanticweb.owl.align.Parameters;
 
 // Alignment API implementation classes
 import fr.inrialpes.exmo.align.impl.BasicParameters;
@@ -38,6 +37,7 @@ import fr.inrialpes.exmo.align.impl.URIAlignment;
 import fr.inrialpes.exmo.align.impl.BasicAlignment;
 import fr.inrialpes.exmo.align.impl.method.StringDistAlignment;
 import fr.inrialpes.exmo.align.impl.renderer.OWLAxiomsRendererVisitor;
+import fr.inrialpes.exmo.align.util.NullStream;
 import fr.inrialpes.exmo.align.parser.AlignmentParser;
 
 // Jena
@@ -51,7 +51,20 @@ import com.hp.hpl.jena.query.ResultSetFormatter;
 import com.hp.hpl.jena.query.QueryExecution;
 import com.hp.hpl.jena.query.QueryExecutionFactory;
 
+// OWL API
+import org.semanticweb.owlapi.model.IRI;
+import org.semanticweb.owlapi.model.OWLOntologyManager;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.semanticweb.owlapi.model.OWLOntologyCreationException;
+import org.semanticweb.owlapi.model.OWLClass;
+import org.semanticweb.owlapi.model.OWLAxiom;
+import org.semanticweb.owlapi.model.OWLClassExpression;
+import org.semanticweb.owlapi.model.OWLNamedIndividual;
+import org.semanticweb.owlapi.apibinding.OWLManager;
+import org.semanticweb.owlapi.reasoner.OWLReasoner;
+
 // Pellet
+import com.clarkparsia.pellet.owlapiv3.PelletReasoner;
 
 // IDDL
 import fr.inrialpes.exmo.iddl.IDDLReasoner;
@@ -79,6 +92,8 @@ import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathConstants;
 
 // Java standard classes
+import java.util.Set;
+import java.util.Properties;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.BufferedWriter;
@@ -87,6 +102,7 @@ import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.InputStream;
 import java.io.FileInputStream;
+import java.io.PrintStream;
 import java.io.FileNotFoundException;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
@@ -105,34 +121,34 @@ import java.net.URISyntaxException;
  * Reconcile two ontologies in various ways
  */
 
-public class MyApp {
+public class Skeleton {
 
     String RESTServ = "http://aserv.inrialpes.fr/rest/";
 
     public static void main( String[] args ) {
-	new MyApp().run( args );
+	new Skeleton().run( args );
     }
 
     public void run( String[] args ) {
-
 	// Setting variables
-	String myId = "JETest";
+	String myId = "Test";
 	Alignment al = null;
 	URI uri1 = null;
 	URI uri2 = null;
-	//String u1 = "http://alignapi.gforge.inria.fr/tutorial4/ontology1.owl";
-	//String u2 = "http://alignapi.gforge.inria.fr/tutorial4/ontology2.owl";
 	String u1 = "file:ontology1.owl";
 	String u2 = "file:ontology2.owl";
 	String method = "fr.inrialpes.exmo.align.impl.method.StringDistAlignment";
-	Parameters params = new BasicParameters();
+	String tempOntoFileName = "results/myresult.owl";
+	Properties params = new BasicParameters();
 	try {
 	    uri1 = new URI( u1 );
 	    uri2 = new URI( u2 );
-	} catch (URISyntaxException use) { use.printStackTrace(); exit(); }
+	} catch (URISyntaxException use) { use.printStackTrace(); System.exit(-1); }
 
 	try {
 
+	    System.out.println( "You are ready to play" );
+
 	    // ***** First exercise: matching *****
 	    // (Sol1) Try to find an alignment between two ontologies from the server
 	    // ask for it
@@ -169,7 +185,9 @@ public class MyApp {
 
 	    // (Sol2) Use Pellet to answer queries (at the ontology level)
 
-	} catch (Exception e) { e.printStackTrace(); exit();  }
+	    // (Sol3) reasoning with distributed semantics (IDDL)
+
+	} catch (Exception e) { e.printStackTrace(); System.exit(-1); }
     }
 
     public String getFromURLString( String u, boolean print ){
@@ -195,7 +213,7 @@ public class MyApp {
     public NodeList extractFromResult( String found, String path, boolean print ){
 	Document document = null;
 	NodeList nodes = null;
-	try { // Parse the returned string as XML
+	try { // Parse the returned stringAS XML
 	    DocumentBuilder parser =
 		DocumentBuilderFactory.newInstance().newDocumentBuilder();
 	    document = parser.parse(new ByteArrayInputStream( found.getBytes() ));
@@ -206,6 +224,7 @@ public class MyApp {
 	try { // Apply the Xpath expression
 	    XPathFactory factory = XPathFactory.newInstance();
 	    XPath xpath = factory.newXPath();
+	    //XPathExpression expr = xpath.compile("//book[author='Neal Stephenson']/title/text()");
 	    XPathExpression expr = xpath.compile( path );
 	    Object result = expr.evaluate( document, XPathConstants.NODESET );
 	    nodes = (NodeList)result;
@@ -218,3 +237,4 @@ public class MyApp {
 	return nodes;
     }
 }
+
diff --git a/html/tutorial/tutorial4/index.html b/html/tutorial/tutorial4/index.html
index 16abf7ed..08210652 100644
--- a/html/tutorial/tutorial4/index.html
+++ b/html/tutorial/tutorial4/index.html
@@ -102,15 +102,14 @@ The list of jars is long, but at least it is explicit and you
 should be safe with this one.
 This programme can be compiled by:
 <div class="fragment">
-$ javac -d results MyApp.java
+$ javac -d results Skeleton.java
 </div>
 </p>
-<p>This
-  programme can be run by:
+<p>This programme can be run by:
 <div class="fragment">
-$ java MyApp
-</div></p>
-You can start with the empty template <a href="Skeleton.java">Skeleton.java</a>.
+$ java Skeleton
+</div>
+It provides no output for the moment.
 </p>
 
 <h2>Matching ontologies</h2>
@@ -135,68 +134,68 @@ and, if none is found, computes one.
   <input type="button" onclick="show('qu1')" value="Show solution 1"/>
   <input type="button" onclick="show('qu2')" value="Show solution 2"/>
   <input type="button" onclick="show('qu3')" value="Show solution 3"/>
-  <input type="button" onclick="hide('qu1');hide('qu2');hide('qu3');" value="Hide solutions"/>
+  <input type="button" onclick="hide('qu0');hide('qu1');hide('qu2');hide('qu3');" value="Hide solutions"/>
 </div>
 <div class="explain" id="qu0">
 <p>After introducing the main variables:</p>
 <pre>
-	String myId = "JETest";
-	Alignment al = null;
-	URI uri1 = null;
-	URI uri2 = null;
-	String u1 = "file:ontology1.owl";
-	String u2 = "file:ontology2.owl";
-	String method = "fr.inrialpes.exmo.align.impl.method.StringDistAlignment";
-	String tempOntoFileName = "/tmp/myresult.owl";
-	Parameters params = new BasicParameters();
-	try {
-	    uri1 = new URI( u1 );
-	    uri2 = new URI( u2 );
-	} catch (URISyntaxException use) { use.printStackTrace(); }
+String myId = "Test";
+Alignment al = null;
+URI uri1 = null;
+URI uri2 = null;
+String u1 = "file:ontology1.owl";
+String u2 = "file:ontology2.owl";
+String method = "fr.inrialpes.exmo.align.impl.method.StringDistAlignment";
+String tempOntoFileName = "results/myresult.owl";
+Properties params = new BasicParameters();
+try {
+  uri1 = new URI( u1 );
+  uri2 = new URI( u2 );
+} catch (URISyntaxException use) { use.printStackTrace(); }
 </pre>
 </div>
 <div class="explain" id="qu1">
 <p>The programme will invoke the alignment server:</p>
 <pre>
-	// (Sol1) Try to find an alignment between two ontologies from the server
-	// ask for it
-	String found = getFromURLString( RESTServ+"find?onto1="+u1+"&onto2="+u2, false );
+// (Sol1) Try to find an alignment between two ontologies from the server
+// ask for it
+String found = getFromURLString( RESTServ+"find?onto1="+u1+"&onto2="+u2, false );
 </pre>
 <p>Retrieve the alignment itself:</p>
 <pre>
-	// retrieve it
-	// If there exists alignments, ask for the first one
-	NodeList alset = extractFromResult( found, "//findResponse/alignmentList/alid[1]/text()", false );
+// retrieve it
+// If there exists alignments, ask for the first one
+NodeList alset = extractFromResult( found, "//findResponse/alignmentList/alid[1]/text()", false );
 </pre>
 <p>And parse it:</p>
 <pre>
-	// parse it as an alignment
-	// (better passing to the SAXHandler)
-	AlignmentParser aparser = new AlignmentParser(0);
-	Alignment alu = aparser.parseString( xmlString );
-	al = ObjectAlignment.toObjectAlignment((URIAlignment)alu);
+// parse it as an alignment
+AlignmentParser aparser = new AlignmentParser(0);
+Alignment alu = aparser.parseString( xmlString );
+al = ObjectAlignment.toObjectAlignment((URIAlignment)alu);
 </pre>
 </div>
-<div class="explain" id="qu2"><p>Just create an instance of
-    AlignmentProcess and call it:</p>
+<div class="explain" id="qu2">
+<p>Just create an instance of AlignmentProcess and call it:</p>
 <pre>
-	// (Sol2) Match the ontologies with a local algorithm
-	if ( al == null ){ // Unfortunatelly no alignment was available
-	    AlignmentProcess ap = new StringDistAlignment();
-	    ap.init( uri1, uri2 );
-	    params.setParameter("stringFunction","smoaDistance");
-	    ap.align( (Alignment)null, params );
-	    al = ap;
-	}
+// (Sol2) Match the ontologies with a local algorithm
+if ( al == null ){ // Unfortunatelly no alignment was available
+  AlignmentProcess ap = new StringDistAlignment();
+  ap.init( uri1, uri2 );
+  params.setProperty("stringFunction","smoaDistance");
+  params.setProperty("noinst","1");
+  ap.align( (Alignment)null, params );
+  al = ap;
+}
 </pre>
 </div>
 <div class="explain" id="qu3"><p>Match on the server:</p>
 <pre>
-	// (Sol3) Match the ontologies on the server
-	if ( alset.getLength() == 0 ) {
-	    // call for matching
-	    String match = getFromURLString( RESTServ+"match?onto1="+u1+"&onto2="+u2+"&method="+method+"&pretty="+myId+"&action=Match&force=true", true );
-	}
+// (Sol3) Match the ontologies on the server
+if ( alset.getLength() == 0 ) {
+  // call for matching
+  String match = getFromURLString( RESTServ+"match?onto1="+u1+"&onto2="+u2+"&method="+method+"&pretty="+myId+"&action=Match", true );
+}
 </pre>
 <p>The remainder is the same as in the first solution.</p>
 </div>
@@ -234,15 +233,16 @@ This can be done with the alignment API support.
 <div class="explain" id="qu5">
 <p>In fact everything is done in one step:</p>
 <pre>
-	// (Sol1) generate a merged ontology between the ontologies (OWLAxioms)
-	File merged = new File( tempOntoFileName );
-	PrintWriter writer = new PrintWriter ( new FileWriter( merged, false ), true );
-	AlignmentVisitor renderer = new OWLAxiomsRendererVisitor(writer);
-	al.render(renderer);
-	writer.flush();
-	writer.close();
+// (Sol1) generate a merged ontology between the ontologies (OWLAxioms)
+PrintWriter writer = null;
+File merged = new File( tempOntoFileName );
+writer = new PrintWriter ( new FileWriter( merged, false ), true );
+AlignmentVisitor renderer = new OWLAxiomsRendererVisitor(writer);
+al.render(renderer);
+writer.flush();
+writer.close();
 </pre>
-<p>You can look at the result in myresult.owl</p>
+<p>You can look at the result in <a href="results/myresult.owl">results/myresult.owl</a>.</p>
 </div>
 <div class="explain" id="qu6"><p>Not ready yet</p>
 <pre>
@@ -264,9 +264,17 @@ This can be done in three ways:
 <p>
 In case you go for SPARQL please, take care of the inference regime
 and observe what are the differences in this case. You can of course
-run various queries and start by runing them in one of the initial
+run various queries and start by running them in one of the initial
 ontologies instead of the merged one.
 </p>
+<p>
+For using Pellet, it will be necessary
+to <a href="http://clarkparsia.com/pellet/download">download
+Pellet</a>  and add in
+the classpath the corresponding pellet-rules.jar,
+pellet-datatypes.jar, pellet-query.jar and pellet-el.jar jar-files
+which are not shipped with the Alignment API.
+</p>
 </p>
 <div class="button">
   <input type="button" onclick="show('qu7')" value="Show solution 1"/>
@@ -277,74 +285,78 @@ ontologies instead of the merged one.
 <div class="explain" id="qu7">
 <p>Prepare the system:</p>
 <pre>
-	// (Sol1) Use SPARQL to answer queries (at the data level)
-	InputStream in = new FileInputStream( merged );
-	//OntModelSpec.OWL_MEM_RDFS_INF or no arguments to see the difference...
-	Model model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF,null);
-	model.read(in,"file:///tmp/myresult.owl"); 
-	in.close();
+// (Sol1) Use SPARQL to answer queries (at the data level)
+InputStream in = new FileInputStream( merged );
+Model model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF,null);
+model.read( in, "file:"+tempOntoFileName );
+in.close();
 </pre>	
 <p>Query (please play by changing the query)</p>
 <pre>
-        // Create a new query
-	String queryString = 
+// Create a new query
+String queryString = 
 		"PREFIX foaf: <http://xmlns.com/foaf/0.1/> " +
 		"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
 		"PREFIX aa: <http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#> " +
-		"SELECT ?fn ?ln ?t " +
+		"SELECT ?fn ?ln ?t ?s " +
 		"WHERE {" +
-                "      ?student rdf:type aa:Person . " +
+                "      ?student rdf:type aa:Estudiante . " +
 		"      ?student aa:firstname  ?fn. " +
 		"      ?student aa:lastname  ?ln. " +
-		"      ?student aa:topic ?t . " +
+		"OPTIONAL   {   ?student aa:affiliation ?t . } " +
+		"OPTIONAL   {   ?student aa:supervisor ?s . } " +
 		"      }";
+
+Query query = QueryFactory.create(queryString);
+
 </pre>	
 <p>Evaluation:</p>
 <pre>
-	Query query = QueryFactory.create(queryString);
+// Execute the query and obtain results
+QueryExecution qe = QueryExecutionFactory.create(query, model);
+ResultSet results = qe.execSelect();
 
-	// Execute the query and obtain results
-	QueryExecution qe = QueryExecutionFactory.create(query, model);
-	ResultSet results = qe.execSelect();
-	
-	// Output query results	
-	ResultSetFormatter.out(System.out, results, query);
+// Output query results	
+ResultSetFormatter.out(System.out, results, query);
 </pre>
 </div>
 <div class="explain" id="qu8">
 <p>Create Reasoner instance and load the merged ontologies:</p>
 <pre>
-	OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
-	Reasoner reasoner = new Reasoner( manager );
-	try {
-	    OWLOntology ontology = manager.loadOntology( URI.create( "file://"+tempOntoFileName ) );
-	    reasoner.loadOntology( ontology );
-	} catch (OWLOntologyCreationException ooce) { ooce.printStackTrace(); }
+OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
+// Load the ontology 
+OWLOntology ontology = manager.loadOntology( IRI.create( "file:"+tempOntoFileName ) );
+OWLReasoner reasoner = new PelletReasoner( ontology, org.semanticweb.owlapi.reasoner.BufferingMode.NON_BUFFERING );
+reasoner.prepareReasoner();
 </pre>
 <p>Get the instances of "Estudiantes":</p>
 <pre>
-	OWLClass estud = manager.getOWLDataFactory().getOWLClass( URI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#Estudiante" ) );   
-	OWLClass person = manager.getOWLDataFactory().getOWLClass( URI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#Person" ) );   
-	OWLClass student = manager.getOWLDataFactory().getOWLClass( URI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#Student" ) );   
-	Set instances  = reasoner.getIndividuals( estud, false );
-	System.err.println("Pellet(Merged): There are "+instances.size()+" students "+estud.getURI());
+// get the instances of a class
+OWLClass estud = manager.getOWLDataFactory().getOWLClass( IRI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#Estudiante" ) );   
+OWLClass person = manager.getOWLDataFactory().getOWLClass( IRI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#Person" ) );   
+OWLClass student = manager.getOWLDataFactory().getOWLClass( IRI.create( "http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#Student" ) );   
+Set<OWLNamedIndividual> instances  = reasoner.getInstances( estud, false ).getFlattened();
+System.err.println("Pellet(Merged): There are "+instances.size()+" students "+clname(estud));
 </pre>
 <p>Some subsumption tests:</p>
 <pre>
-	testPelletSubClass( manager, reasoner, estud, person );
-	testPelletSubClass( manager, reasoner, estud, student );
+testPelletSubClass( manager, reasoner, estud, person );
+testPelletSubClass( manager, reasoner, estud, student );
 </pre>
 <p>Such that:</p>
 <pre>
-    public void testPelletSubClass( OWLOntologyManager manager, Reasoner reasoner, OWLDescription d1, OWLDescription d2 ) {
-	OWLAxiom axiom = manager.getOWLDataFactory().getOWLSubClassAxiom( d1, d2 );
-	boolean isit = reasoner.isEntailed( axiom );
-	if ( isit ) {
-	    System.out.println( "Pellet(Merged): "+d1+" is subclass of "+d2 );
-	} else {
-	    System.out.println( "Pellet(Merged): "+d1+" is not necessarily subclass of "+d2 );
-	}
-    }
+private String clname( OWLClassExpression cl ) {
+  return cl.asOWLClass().getIRI().getFragment();
+}
+
+public void testPelletSubClass( OWLOntologyManager manager, OWLReasoner reasoner, OWLClassExpression d1, OWLClassExpression d2 ) {
+  OWLAxiom axiom = manager.getOWLDataFactory().getOWLSubClassOfAxiom( d1, d2 );
+  if ( reasoner.isEntailed( axiom ) ) {
+    System.out.println( "Pellet(Merged): "+clname(d1)+" is subclass of "+clname(d2) );
+  } else {
+    System.out.println( "Pellet(Merged): "+clname(d1)+" is not necessarily subclass of "+clname(d2) );
+  }
+}
 </pre>
 </div>
 <div class="explain" id="qu9">
@@ -382,8 +394,17 @@ ontologies instead of the merged one.
     }
 </pre>
 </div>
-
-The results for these execution are (for Pellet):
+The results for these execution are, for SPARQL:
+<pre>
+---------------------------------------------------------------------------------------
+| fn      | ln      | t                            | s                                |
+=======================================================================================
+| "Miles" | "Davis" | "JOHANNISBEER RESEARCH"      | "Univ.-Prof. Dr. Paolo Carciofo" |
+| "Chet"  | "Baker" | "University Pie XXIII"       |                                  |
+| "McCoy" | "Tyner" | "University of Soupaloignon" | "Dr Nanni Girasole"              |
+...
+</pre>
+for Pellet:
 <pre>
 Pellet(Merged): There are 47 students http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#Estudiante
 Pellet(Merged): Estudiante is not necessarily subclass of Person
diff --git a/html/tutorial/tutorial4/results/myresult.owl b/html/tutorial/tutorial4/results/myresult.owl
new file mode 100644
index 00000000..b2f03a13
--- /dev/null
+++ b/html/tutorial/tutorial4/results/myresult.owl
@@ -0,0 +1,45 @@
+<rdf:RDF
+    xmlns:owl="http://www.w3.org/2002/07/owl#"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" 
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
+
+  <owl:Ontology rdf:about="">
+    <rdfs:comment>Matched ontologies</rdfs:comment>
+    <rdfs:comment>Generated by fr.inrialpes.exmo.align.renderer.OWLAxiomsRendererVisitor</rdfs:comment>
+    <rdfs:comment>method: fr.inrialpes.exmo.align.impl.method.StringDistAlignment</rdfs:comment>
+    <owl:imports rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl"/>
+    <owl:imports rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl"/>
+  </owl:Ontology>
+
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#supervisor">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#phd-advisor"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#city">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#city-of-study"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#affiliation">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#institution"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#topic">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#topics-of-interest"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#firstname">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#first-name"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#lastname">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#name"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#year">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#year-in-phd"/>
+  </owl:DatatypeProperty>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#gender">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#gender"/>
+  </owl:DatatypeProperty>
+  <owl:Class rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#Estudiante">
+    <owl:equivalentClass rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#Student"/>
+  </owl:Class>
+  <owl:DatatypeProperty rdf:about="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology1.owl#country">
+    <owl:equivalentProperty rdf:resource="http://alignapi.gforge.inria.fr/tutorial/tutorial4/ontology2.owl#country-of-study"/>
+  </owl:DatatypeProperty>
+</rdf:RDF>
-- 
GitLab