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.kb.sparql;
020
021import java.net.URI;
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Random;
026import java.util.Set;
027import java.util.TreeSet;
028import java.util.stream.Collectors;
029
030import org.dllearner.algorithms.el.ELLearningAlgorithm;
031import org.dllearner.core.StringRenderer;
032import org.dllearner.kb.OWLAPIOntology;
033import org.dllearner.kb.OWLOntologyKnowledgeSource;
034import org.dllearner.kb.SparqlEndpointKS;
035import org.dllearner.learningproblems.ClassLearningProblem;
036import org.dllearner.reasoning.ClosedWorldReasoner;
037import org.dllearner.reasoning.OWLAPIReasoner;
038import org.dllearner.reasoning.ReasonerImplementation;
039import org.dllearner.utilities.examples.AutomaticNegativeExampleFinderSPARQL2;
040import org.mindswap.pellet.PelletOptions;
041import org.openrdf.model.vocabulary.RDF;
042import org.semanticweb.owlapi.apibinding.OWLManager;
043import org.semanticweb.owlapi.model.*;
044
045import org.semanticweb.owlapi.owlxml.renderer.OWLXMLObjectRenderer;
046import uk.ac.manchester.cs.owl.owlapi.OWLClassImpl;
047import uk.ac.manchester.cs.owl.owlapi.OWLNamedIndividualImpl;
048
049import com.google.common.collect.Sets;
050import org.apache.jena.query.QueryExecution;
051import org.apache.jena.query.QuerySolution;
052import org.apache.jena.query.ResultSet;
053
054/**
055 * Computes a sample fragment of the knowledge base given an OWL class.
056 * @author Lorenz Buehmann
057 *
058 */
059public class ClassBasedSampleGenerator extends InstanceBasedSampleGenerator{
060        
061        private Random rnd = new Random(12345);
062        
063        private int maxNrOfPosExamples = 20;
064        private int maxNrOfNegExamples = 20;
065        
066        private boolean useNegExamples = true;
067        
068        private AutomaticNegativeExampleFinderSPARQL2 negExamplesFinder;
069        
070        private Set<OWLIndividual> posExamples;
071        private Set<OWLIndividual> negExamples;
072
073        public ClassBasedSampleGenerator(SparqlEndpointKS ks) {
074                super(ks);
075                
076                negExamplesFinder = new AutomaticNegativeExampleFinderSPARQL2(qef);
077        }
078
079        /**
080         * Computes a sample fragment of the knowledge base by using instances of the
081         * given OWL class and also, if enabled, use some instances that do not belong to the class.
082         * @param cls the OWL class
083         * @return a sample fragment
084         */
085        public OWLOntology getSample(OWLClass cls) {
086                // get positive examples
087                posExamples = computePosExamples(cls);
088                
089                // get negative examples if enabled
090                negExamples = computeNegExamples(cls, posExamples);
091                
092                // compute sample based on positive (and negative) examples
093                return getSample(Sets.union(posExamples, negExamples));
094        }
095
096        /**
097         * @param maxNrOfPosExamples the max. number of pos. examples used for sampling
098         */
099        public void setMaxNrOfPosExamples(int maxNrOfPosExamples) {
100                this.maxNrOfPosExamples = maxNrOfPosExamples;
101        }
102
103        /**
104         * @param maxNrOfNegExamples the max. number of neg. examples used for sampling
105         */
106        public void setMaxNrOfNegExamples(int maxNrOfNegExamples) {
107                this.maxNrOfNegExamples = maxNrOfNegExamples;
108        }
109
110        /**
111         * @param useNegExamples whether to use negative examples or not
112         */
113        public void setUseNegExamples(boolean useNegExamples) {
114                this.useNegExamples = useNegExamples;
115        }
116        
117        /**
118         * @return the positive examples, i.e. instances of the class used to
119         * generate the sample
120         */
121        public Set<OWLIndividual> getPositiveExamples() {
122                return posExamples;
123        }
124        
125        /**
126         * @return the negative examples, i.e. individuals that do not belong to the class and are used to
127         * generate the sample
128         */
129        public Set<OWLIndividual> getNegativeExamples() {
130                return negExamples;
131        }
132
133        /**
134         * The examples for the sample are chosen randomly, thus, the seed for shuffling can be set here.
135         * @see Random#setSeed(long)
136         * @param seed the seed
137         */
138        public void setSeed(long seed) {
139                rnd.setSeed(seed);
140        }
141
142        private Set<OWLIndividual> computePosExamples(OWLClass cls) {
143                List<OWLIndividual> posExamples = new ArrayList<>();
144                
145                String query = String.format("SELECT ?s WHERE {?s a <%s>}", cls.toStringID());
146
147                try(QueryExecution qe = qef.createQueryExecution(query)) {
148                        ResultSet rs = qe.execSelect();
149                        while(rs.hasNext()) {
150                                QuerySolution qs = rs.next();
151                                posExamples.add(new OWLNamedIndividualImpl(IRI.create(qs.getResource("s").getURI())));
152                        }
153                }
154
155                Collections.shuffle(posExamples, rnd);
156                
157                return new TreeSet<>(posExamples.subList(0, Math.min(posExamples.size(), maxNrOfPosExamples)));
158        }
159        
160        private Set<OWLIndividual> computeNegExamples(OWLClass cls, Set<OWLIndividual> posExamples) {
161                Set<OWLIndividual> negExamples = new TreeSet<>();
162                
163                if(useNegExamples && maxNrOfPosExamples > 0) {
164                        negExamples = negExamplesFinder.getNegativeExamples(cls, posExamples, maxNrOfNegExamples);
165                }
166                
167                return negExamples;
168        }
169
170        public static void main(String[] args) throws Exception{
171                StringRenderer.setRenderer(StringRenderer.Rendering.DL_SYNTAX);
172
173                SparqlEndpoint endpoint = SparqlEndpoint.create("http://dbpedia.org/sparql", "http://dbpedia.org");
174                SparqlEndpointKS ks = new SparqlEndpointKS(endpoint);
175                ks.setUseCache(false);
176                ks.setRetryCount(0);
177                ks.init();
178                OWLOntologyManager man = OWLManager.createOWLOntologyManager();
179//              OWLOntology schema = man.createOntology();//man.loadOntology(IRI.create("http://downloads.dbpedia.org/2016-10/dbpedia_2016-10.nt"));
180                OWLOntology schema = man.loadOntology(IRI.create("http://downloads.dbpedia.org/2016-10/dbpedia_2016-10.nt"));
181
182                ClassBasedSampleGenerator sampleGenerator = new ClassBasedSampleGenerator(ks);
183                sampleGenerator.setUseNegExamples(false);
184                sampleGenerator.setSampleDepth(2);
185                sampleGenerator.addAllowedPropertyNamespaces(Sets.newHashSet("http://dbpedia.org/ontology/"));
186                sampleGenerator.addAllowedObjectNamespaces(Sets.newHashSet("http://dbpedia.org/ontology/", "http://dbpedia.org/resource/"));
187
188                PelletOptions.INVALID_LITERAL_AS_INCONSISTENCY = false;
189                OWLClass cls = new OWLClassImpl(IRI.create("http://dbpedia.org/ontology/Book"));
190
191                // generate a class based sample
192                OWLOntology sample = sampleGenerator.getSample(cls);
193                man.addAxioms(sample, schema.getLogicalAxioms());
194
195                Set<String> ignoredProperties = Sets.newHashSet(
196                                "http://dbpedia.org/ontology/abstract","http://dbpedia.org/ontology/birthName",
197                                "http://dbpedia.org/ontology/wikiPageID",
198                                "http://dbpedia.org/ontology/wikiPageRevisionID",
199                                "http://dbpedia.org/ontology/wikiPageID");
200                OWLOntology ont = man.createOntology(schema.getAxioms());
201                man.addAxioms(ont, sample.getLogicalAxioms().stream().filter(ax -> {
202                        if(ax.getAxiomType() == AxiomType.OBJECT_PROPERTY_ASSERTION) {
203                                return true;
204                        } else if(ax.getAxiomType() == AxiomType.DATA_PROPERTY_ASSERTION) {
205                                return !ignoredProperties.contains(((OWLDataPropertyAssertionAxiom)ax).getProperty().asOWLDataProperty().toStringID());
206                        }
207                        return true;
208                }).collect(Collectors.toSet()));
209
210//              System.out.println("|Sample|=" + sample.getLogicalAxiomCount());
211//              sample.getLogicalAxioms().forEach(System.out::println);
212
213                OWLOntologyKnowledgeSource sampleKS = new OWLAPIOntology(ont);
214                sampleKS.init();
215
216                OWLAPIReasoner baseReasoner = new OWLAPIReasoner(sampleKS);
217                baseReasoner.setReasonerImplementation(ReasonerImplementation.STRUCTURAL);
218                baseReasoner.init();
219
220                ClosedWorldReasoner reasoner = new ClosedWorldReasoner(baseReasoner);
221//                    reasoner.setReasonerComponent(baseReasoner);
222                reasoner.init();
223
224                ClassLearningProblem lp = new ClassLearningProblem(reasoner);
225                lp.setClassToDescribe(cls);
226                lp.setEquivalence(false);
227                lp.setCheckConsistency(false);
228                lp.init();
229
230                ELLearningAlgorithm la = new ELLearningAlgorithm(lp, reasoner);
231                la.setClassToDescribe(cls);
232                la.setNoisePercentage(90);
233                la.setMaxNrOfResults(50);
234                la.setMaxExecutionTimeInSeconds(10);
235//              la.setStartClass(cls);
236                la.init();
237
238                la.start();
239        }
240}