001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.algorithms.pattern;
020
021import com.google.common.collect.HashMultiset;
022import com.google.common.collect.Multiset;
023import org.apache.jena.query.*;
024import org.apache.jena.rdf.model.Model;
025import org.apache.jena.rdf.model.ModelFactory;
026import org.apache.jena.rdf.model.Resource;
027import org.apache.jena.vocabulary.RDF;
028import org.dllearner.core.AbstractAxiomLearningAlgorithm;
029import org.dllearner.core.ComponentAnn;
030import org.dllearner.core.Score;
031import org.dllearner.kb.SparqlEndpointKS;
032import org.dllearner.kb.sparql.SparqlEndpoint;
033import org.dllearner.utilities.owl.OWLClassExpressionToSPARQLConverter;
034import org.semanticweb.owlapi.model.*;
035import org.semanticweb.owlapi.util.DefaultPrefixManager;
036import org.semanticweb.owlapi.util.OWLObjectDuplicator;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
040
041import java.io.ByteArrayInputStream;
042import java.io.InputStream;
043import java.util.*;
044import java.util.Map.Entry;
045import java.util.concurrent.TimeUnit;
046
047/**
048 * @author Lorenz Buehmann
049 *
050 */
051@ComponentAnn(name = "pattern-based learner", shortName = "patla", version = 0.1, description = "Pattern-based algorithm uses OWL axioms as pattern.")
052public class PatternBasedAxiomLearningAlgorithm extends AbstractAxiomLearningAlgorithm<OWLAxiom, OWLObject, OWLEntity>{
053        
054        private static final Logger logger = LoggerFactory.getLogger(PatternBasedAxiomLearningAlgorithm.class);
055        
056        
057        private OWLAxiom pattern;
058        private OWLClass cls;
059        
060        private FragmentExtractor fragmentExtractor;
061        private OWLClassExpressionToSPARQLConverter converter = new OWLClassExpressionToSPARQLConverter();
062        private OWLDataFactory dataFactory = new OWLDataFactoryImpl();
063        
064        private OWLAnnotationProperty confidenceProperty = dataFactory.getOWLAnnotationProperty(IRI.create("http://dl-learner.org/pattern/confidence"));
065
066        private double threshold = 0.4;
067        
068        public PatternBasedAxiomLearningAlgorithm(SparqlEndpointKS ks, FragmentExtractionStrategy extractionStrategy) {
069                this.ks = ks;
070
071                if(extractionStrategy == FragmentExtractionStrategy.TIME){
072                        fragmentExtractor = new TimeBasedFragmentExtractor(ks, 20, TimeUnit.SECONDS);
073                } else if(extractionStrategy == FragmentExtractionStrategy.INDIVIDUALS){
074                        fragmentExtractor = new IndividualBasedFragmentExtractor(ks, 20);
075                }
076        }
077        
078        public PatternBasedAxiomLearningAlgorithm(SparqlEndpointKS ks, String cacheDir, FragmentExtractionStrategy extractionStrategy) {
079
080        }
081
082        /**
083         * @param pattern the pattern to set
084         */
085        public void setPattern(OWLAxiom pattern) {
086                this.pattern = pattern;
087        }
088        
089        /**
090         * @param cls the cls to set
091         */
092        public void setClass(OWLClass cls) {
093                this.cls = cls;
094        }
095        
096        /* (non-Javadoc)
097         * @see org.dllearner.core.AbstractAxiomLearningAlgorithm#getExistingAxioms()
098         */
099        @Override
100        protected void getExistingAxioms() {
101        }
102        
103        /* (non-Javadoc)
104         * @see org.dllearner.core.AbstractAxiomLearningAlgorithm#getSampleQuery()
105         */
106        @Override
107        protected ParameterizedSparqlString getSampleQuery() {
108                return null;
109        }
110        
111        /* (non-Javadoc)
112         * @see org.dllearner.core.AbstractAxiomLearningAlgorithm#learnAxioms()
113         */
114        @Override
115        protected void learnAxioms() {
116                logger.info("Pattern: " + pattern);
117                
118                //get the maximum modal depth in the pattern axioms
119                int modalDepth = MaximumModalDepthDetector.getMaxModalDepth(pattern);modalDepth++;
120                logger.info("Modal depth: " + modalDepth);
121                
122                //extract fragment
123                Model fragment = fragmentExtractor.extractFragment(cls, modalDepth);
124                
125                //try to find instantiation of the pattern with confidence above threshold
126                Set<OWLAxiom> instantiations = applyPattern(pattern, dataFactory.getOWLClass(IRI.create(cls.toStringID())), fragment);
127                for (OWLAxiom instantiation : instantiations) {
128                        System.out.println(instantiation);
129                }
130        }
131        
132        private Set<OWLAxiom> applyPattern(OWLAxiom pattern, OWLClass cls, Model fragment) {
133                Map<OWLAxiom, Score> axioms2Score = new HashMap<>();
134                
135                OWLClassExpression patternSubClass = null;
136                OWLClassExpression patternSuperClass = null;
137                
138                if(pattern.isOfType(AxiomType.EQUIVALENT_CLASSES)){
139                        Set<OWLSubClassOfAxiom> subClassOfAxioms = ((OWLEquivalentClassesAxiom)pattern).asOWLSubClassOfAxioms();
140                        for (OWLSubClassOfAxiom axiom : subClassOfAxioms) {
141                                if(!axiom.getSubClass().isAnonymous()){
142                                        patternSubClass = axiom.getSubClass();
143                                        patternSuperClass = axiom.getSuperClass();
144                                        break;
145                                }
146                        }
147                } else if(pattern.isOfType(AxiomType.SUBCLASS_OF)){
148                        patternSubClass = ((OWLSubClassOfAxiom) pattern).getSubClass();
149                        patternSuperClass = ((OWLSubClassOfAxiom) pattern).getSuperClass();
150                } else {
151                        logger.warn("Pattern " + pattern + " not supported yet.");
152                        return Collections.emptySet();
153                }
154                
155                Set<OWLEntity> signature = patternSuperClass.getSignature();
156                signature.remove(patternSubClass.asOWLClass());
157                Query query = converter.asQuery("?x", dataFactory.getOWLObjectIntersectionOf(cls, patternSuperClass), signature);
158                logger.info("Running query\n" + query);
159                Map<OWLEntity, String> variablesMapping = converter.getVariablesMapping();
160                org.apache.jena.query.ResultSet rs = QueryExecutionFactory.create(query, fragment).execSelect();
161                QuerySolution qs;
162                Set<String> resources = new HashSet<>();
163                Multiset<OWLAxiom> instantiations = HashMultiset.create();
164                while (rs.hasNext()) {
165                        qs = rs.next();
166                        resources.add(qs.getResource("x").getURI());
167                        // get the IRIs for each variable
168                        Map<OWLEntity, IRI> entity2IRIMap = new HashMap<>();
169                        entity2IRIMap.put(patternSubClass.asOWLClass(), cls.getIRI());
170                        boolean skip = false;
171                        for (OWLEntity entity : signature) {
172                                String var = variablesMapping.get(entity);
173                                if(qs.get(var) == null){
174                                        logger.warn("Variable " + var + " is not bound.");
175                                        skip = true;
176                                        break;
177                                }
178                                if(qs.get(var).isLiteral()){
179                                        skip = true;
180                                        break;
181                                }
182                                Resource resource = qs.getResource(var);
183                                if(entity.isOWLObjectProperty() && resource.hasURI(RDF.type.getURI())){
184                                        skip = true;
185                                        break;
186                                }
187                                entity2IRIMap.put(entity, IRI.create(resource.getURI()));
188                        }
189                        if(!skip){
190                                // instantiate the pattern
191                                OWLObjectDuplicator duplicator = new OWLObjectDuplicator(entity2IRIMap, dataFactory);
192                                OWLAxiom patternInstantiation = duplicator.duplicateObject(pattern);
193                                instantiations.add(patternInstantiation);
194                        }
195                }
196                // compute the score
197                int total = resources.size();
198                for (OWLAxiom axiom : instantiations.elementSet()) {
199                        int frequency = instantiations.count(axiom);
200//                      System.out.println(axiom + ":" + frequency);
201                        Score score = computeScore(total, Math.min(total, frequency));
202                        axioms2Score.put(axiom, score);
203                }
204
205                return asAnnotatedAxioms(axioms2Score);
206        }
207        
208        private Set<OWLAxiom> asAnnotatedAxioms(Map<OWLAxiom, Score> axioms2Score){
209                Set<OWLAxiom> annotatedAxioms = new HashSet<>();
210                for (Entry<OWLAxiom, Score> entry : axioms2Score.entrySet()) {
211                        OWLAxiom axiom = entry.getKey();
212                        Score score = entry.getValue();
213                        if(score.getAccuracy() >= threshold){
214                                annotatedAxioms.add(axiom.getAnnotatedAxiom(
215                                                Collections.singleton(dataFactory.getOWLAnnotation(confidenceProperty, dataFactory.getOWLLiteral(score.getAccuracy())))));
216                                
217                        }
218                }
219                return annotatedAxioms;
220        }
221        
222        public static void main(String[] args) throws Exception {
223                OWLDataFactoryImpl df = new OWLDataFactoryImpl();
224                PrefixManager pm = new DefaultPrefixManager();
225                pm.setDefaultPrefix("http://dllearner.org/pattern#");
226                
227                Model model = ModelFactory.createDefaultModel();
228                String triples = 
229                                "<http://ex.org/a> a <http://ex.org/A>."+
230                                "<http://ex.org/a> <http://ex.org/p> <http://ex.org/y1>."+
231                                "<http://ex.org/y1> a <http://ex.org/B>."+
232                                
233                                "<http://ex.org/b> a <http://ex.org/A>."+
234                                "<http://ex.org/b> <http://ex.org/p> <http://ex.org/y2>."+
235                                "<http://ex.org/y2> a <http://ex.org/B>."+
236                                
237                                "<http://ex.org/c> a <http://ex.org/A>."
238                                ;
239                InputStream is = new ByteArrayInputStream( triples.getBytes("UTF-8"));
240                model.read(is, null, "TURTLE");
241                
242                String query = "SELECT DISTINCT   ?x WHERE  { "
243                                + "?x a <http://ex.org/A> .}";
244                
245                ResultSet rs = QueryExecutionFactory.create(query, model).execSelect();
246                System.out.println(ResultSetFormatter.asText(rs));
247                
248                query = "SELECT DISTINCT  ?p0 ?cls0 ?x WHERE  { "
249                                + "?x a <http://ex.org/A> ."
250                                + "?x ?p0 ?s0    "
251                                + "    { SELECT  ?x ?p0 ?cls0 (count(?s1) AS ?cnt1)"
252                                + "      WHERE"
253                                + "        { ?x ?p0 ?s1 ."
254                                + "          ?s1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?cls0"
255                                + "        }"
256                                + "      GROUP BY ?x ?cls0 ?p0"
257                                + "    }"
258                                + "    { SELECT  ?x ?p0 (count(?s2) AS ?cnt2)"
259                                + "      WHERE"
260                                + "        { ?x ?p0 ?s2 }"
261                                + "      GROUP BY ?x ?p0"
262                                + "    }"
263                                + "    FILTER ( ?cnt1 = ?cnt2 )  }";
264                
265                query = "SELECT ?x WHERE {?x a <http://ex.org/A>. FILTER NOT EXISTS{?x <http://ex.org/p> ?s1. FILTER NOT EXISTS{?s1 a <http://ex.org/B>.}}} ";
266                
267                rs = QueryExecutionFactory.create(query, model).execSelect();
268                System.out.println(ResultSetFormatter.asText(rs));
269                
270                SparqlEndpoint endpoint = SparqlEndpoint.getEndpointDBpedia();
271//              endpoint = SparqlEndpoint.getEndpointDBpediaLOD2Cloud();
272//              endpoint = SparqlEndpoint.getEndpointDBpediaLiveAKSW();
273                OWLClass cls = df.getOWLClass(IRI.create("http://dbpedia.org/ontology/SoccerPlayer"));
274                OWLAxiom pattern = df.getOWLSubClassOfAxiom(df.getOWLClass("A", pm),
275                                df.getOWLObjectAllValuesFrom(df.getOWLObjectProperty("p", pm), df.getOWLClass("B", pm)));
276                
277                PatternBasedAxiomLearningAlgorithm la = new PatternBasedAxiomLearningAlgorithm(new SparqlEndpointKS(endpoint), "cache", FragmentExtractionStrategy.INDIVIDUALS);
278                la.setClass(cls);
279                la.setPattern(pattern);
280                la.start();
281        }
282}