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.core;
020
021import org.aksw.jena_sparql_api.core.QueryExecutionFactory;
022import org.aksw.jena_sparql_api.model.QueryExecutionFactoryModel;
023import org.apache.jena.ontology.OntClass;
024import org.apache.jena.query.ParameterizedSparqlString;
025import org.apache.jena.query.Query;
026import org.apache.jena.query.QueryExecution;
027import org.apache.jena.query.ResultSet;
028import org.apache.jena.rdf.model.Literal;
029import org.apache.jena.rdf.model.Model;
030import org.apache.jena.rdf.model.ModelFactory;
031import org.apache.jena.rdf.model.RDFNode;
032import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
033import org.apache.jena.sparql.resultset.ResultSetMem;
034import org.apache.jena.vocabulary.OWL2;
035import org.apache.jena.vocabulary.RDF;
036import org.apache.jena.vocabulary.RDFS;
037import org.dllearner.algorithms.properties.ObjectPropertyCharacteristicsAxiomLearner;
038import org.dllearner.core.annotations.NoConfigOption;
039import org.dllearner.core.annotations.Unused;
040import org.dllearner.core.config.ConfigOption;
041import org.dllearner.core.owl.ClassHierarchy;
042import org.dllearner.kb.LocalModelBasedSparqlEndpointKS;
043import org.dllearner.kb.SparqlEndpointKS;
044import org.dllearner.kb.sparql.SPARQLTasks;
045import org.dllearner.learningproblems.AxiomScore;
046import org.dllearner.learningproblems.Heuristics;
047import org.dllearner.reasoning.SPARQLReasoner;
048import org.dllearner.utilities.OWLAPIUtils;
049import org.semanticweb.owlapi.model.*;
050import org.slf4j.Logger;
051import org.slf4j.LoggerFactory;
052import org.springframework.beans.factory.annotation.Autowired;
053import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
054
055import java.math.RoundingMode;
056import java.net.SocketTimeoutException;
057import java.text.DecimalFormat;
058import java.text.NumberFormat;
059import java.util.*;
060import java.util.Map.Entry;
061import java.util.function.Predicate;
062import java.util.stream.Collectors;
063
064//import org.apache.jena.util.iterator.Filter;
065
066/**
067 * @author Lorenz Bühmann
068 * @author Jens Lehmann
069 */
070public abstract class AbstractAxiomLearningAlgorithm<T extends OWLAxiom, S extends OWLObject, E extends OWLEntity> extends AbstractComponent implements AxiomLearningAlgorithm<T>{
071        
072        @Unused
073        protected LearningProblem learningProblem;
074        protected final Logger logger;
075        
076        protected NumberFormat format = DecimalFormat.getPercentInstance(Locale.ROOT);
077        
078        @ConfigOption(defaultValue="10", description="maximum execution of the algorithm in seconds (abstract)")
079        protected int maxExecutionTimeInSeconds = 10;
080        @ConfigOption(defaultValue="false", description="omit axioms already existing in the knowledge base")
081        protected boolean returnOnlyNewAxioms;
082        @ConfigOption(description="The maximum number of rows fetched from the endpoint to approximate the result.")
083        protected int maxFetchedRows;
084        
085        @ConfigOption(description = "the sparql endpoint knowledge source")
086        protected SparqlEndpointKS ks;
087        
088        // the instances which are set
089        private SPARQLReasoner ksReasoner;
090        private QueryExecutionFactory ksQef;
091        
092        // the instances on which the algorithms are really applied
093        @ConfigOption(description = "The sparql reasoner instance to use", defaultValue = "SPARQLReasoner")
094        protected SPARQLReasoner reasoner;
095        protected QueryExecutionFactory qef;
096        
097        
098        protected SortedSet<EvaluatedAxiom<T>> currentlyBestAxioms;
099        protected SortedSet<T> existingAxioms;
100        
101        protected long startTime;
102        
103        protected boolean timeout = true;
104        
105        @Unused
106        protected boolean forceSPARQL_1_0_Mode = false;
107        
108        protected int chunkCount = 0;
109        protected int chunkSize = 1000;
110        protected int offset = 0;
111        protected int lastRowCount = 0;
112        
113        protected boolean fullDataLoaded = false;
114        
115        protected List<String> allowedNamespaces = new ArrayList<>();
116        
117        protected ParameterizedSparqlString iterativeQueryTemplate;
118        
119        protected Model sample;
120        
121        protected ParameterizedSparqlString posExamplesQueryTemplate;
122        protected ParameterizedSparqlString negExamplesQueryTemplate;
123        protected ParameterizedSparqlString existingAxiomsTemplate;
124        
125        protected OWLDataFactory df = new OWLDataFactoryImpl();
126
127        @NoConfigOption
128//      protected AxiomLearningProgressMonitor progressMonitor = new SilentAxiomLearningProgressMonitor();
129        protected AxiomLearningProgressMonitor progressMonitor = new ConsoleAxiomLearningProgressMonitor();
130        
131        protected AxiomType<T> axiomType;
132        
133        @ConfigOption(description = "the OWL entity to learn about")
134        protected E entityToDescribe;
135        
136        @Unused
137        protected boolean useSampling = true;
138        protected int popularity;
139        
140        public AbstractAxiomLearningAlgorithm() {
141                existingAxioms = new TreeSet<>();
142                
143                logger = LoggerFactory.getLogger(this.getClass());
144        }
145
146        @NoConfigOption
147        public void setQueryExecutionFactory(QueryExecutionFactory qef) {
148                this.ksQef = qef;
149        }
150        
151        @Override
152    public LearningProblem getLearningProblem() {
153        return learningProblem;
154    }
155
156    @Autowired
157    @Override
158    public void setLearningProblem(LearningProblem learningProblem) {
159        this.learningProblem = learningProblem;
160    }
161    
162    /**
163         * @param entityToDescribe the entity for which axioms will be computed
164         */
165        public void setEntityToDescribe(E entityToDescribe) {
166                this.entityToDescribe = entityToDescribe;
167        }
168        
169        /**
170         * @return the entity for which axioms will be computed
171         */
172        public E getEntityToDescribe() {
173                return entityToDescribe;
174        }
175        
176        public void setUseSampling(boolean useSampling) {
177                this.useSampling = useSampling;
178        }
179        
180        public boolean isUseSampling() {
181                return useSampling;
182        }
183    
184    /**
185         * @return the axiomType
186         */
187        public AxiomType<T> getAxiomType() {
188                return axiomType;
189        }
190        
191        public int getMaxExecutionTimeInSeconds() {
192                return maxExecutionTimeInSeconds;
193        }
194
195        public void setMaxExecutionTimeInSeconds(int maxExecutionTimeInSeconds) {
196                this.maxExecutionTimeInSeconds = maxExecutionTimeInSeconds;
197        }
198
199        public SPARQLReasoner getReasoner() {
200                return reasoner;
201        }
202
203        public void setReasoner(SPARQLReasoner reasoner) {
204                this.ksReasoner = reasoner;
205        }
206
207        public boolean isReturnOnlyNewAxioms() {
208                return returnOnlyNewAxioms;
209        }
210
211        public void setReturnOnlyNewAxioms(boolean returnOnlyNewAxioms) {
212                this.returnOnlyNewAxioms = returnOnlyNewAxioms;
213        }
214        
215        public int getMaxFetchedRows() {
216                return maxFetchedRows;
217        }
218
219        public void setMaxFetchedRows(int maxFetchedRows) {
220                this.maxFetchedRows = maxFetchedRows;
221        }
222        
223        public void setForceSPARQL_1_0_Mode(boolean forceSPARQL_1_0_Mode) {
224                this.forceSPARQL_1_0_Mode = forceSPARQL_1_0_Mode;
225        }
226
227        @Override
228        public void start() {
229                logger.info("Started learning of " + axiomType.getName() + " axioms for " +
230                                OWLAPIUtils.getPrintName(entityToDescribe.getEntityType()) + " " + entityToDescribe.toStringID() + "...");
231                startTime = System.currentTimeMillis();
232                
233                currentlyBestAxioms = new TreeSet<>();
234
235                // check whether the knowledge base contains information about the entity, if not terminate
236                popularity = reasoner.getPopularity(entityToDescribe);
237                if(popularity == 0){
238                        logger.warn("Cannot make " + axiomType.getName() + " axiom suggestions for empty " + OWLAPIUtils.getPrintName(entityToDescribe.getEntityType()) + " " + entityToDescribe.toStringID());
239                        return;
240                }
241
242                // if enabled, we check for existing axioms that will filtered out in the final result
243                if(returnOnlyNewAxioms){
244                        getExistingAxioms();
245                }
246
247                // if enabled, we generated a sample of the knowledge base and do the rest of the compuatation locally
248                if(useSampling){
249                        generateSample();
250                } else {
251                        qef = ksQef;
252                        reasoner = ksReasoner;
253                }
254
255                // compute the axiom type specific popularity of the entity to describe
256                popularity = getPopularity();
257
258                // start the real learning algorithm
259                progressMonitor.learningStarted(axiomType);
260                try {
261                        learnAxioms();
262                } catch (Exception e) {
263                        progressMonitor.learningFailed(axiomType);
264                        throw e;
265                } finally {
266                        progressMonitor.learningStopped(axiomType);
267                }
268                
269                logger.info("...finished learning of " + axiomType.getName()
270                                + " axioms for " + OWLAPIUtils.getPrintName(entityToDescribe.getEntityType())
271                                + " " + entityToDescribe.toStringID() + " in {}ms.", (System.currentTimeMillis() - startTime));
272
273                showResult();
274
275        }
276
277        protected void showResult() {
278                DecimalFormat format = new DecimalFormat("0.0000");
279                format.setRoundingMode(RoundingMode.DOWN);
280                if(this instanceof ObjectPropertyCharacteristicsAxiomLearner){
281                        logger.info("Suggested axiom: " + currentlyBestAxioms.first());
282                } else {
283                        logger.info("Found " + currentlyBestAxioms.size() + " axiom candidates. " +
284                                                                (returnOnlyNewAxioms
285                                                                                ? currentlyBestAxioms.size() - existingAxioms.size() +
286                                                                                " out of them do not already exists in the knowledge base."
287                                                                                : ""));
288                        if(!currentlyBestAxioms.isEmpty()){
289                                EvaluatedAxiom<T> bestAxiom = currentlyBestAxioms.last();
290                                String s = "Best axiom candidate is " + bestAxiom.hypothesis + " with an accuracy of " +
291                                                format.format(bestAxiom.getAccuracy());
292                                if(returnOnlyNewAxioms) {
293                                        if(existingAxioms.contains(bestAxiom.hypothesis)) {
294                                                s += ", but it's already contained in the knowledge base.";
295                                                if(existingAxioms.size() != currentlyBestAxioms.size()) {
296                                                        Optional<EvaluatedAxiom<T>> bestNewAxiom = currentlyBestAxioms.stream().filter(
297                                                                        ax -> !existingAxioms.contains(ax.hypothesis)).findFirst();
298                                                        if(bestNewAxiom.isPresent()) {
299                                                                s += " The best new one is " + bestNewAxiom.get().hypothesis + " with an accuracy of " +
300                                                                                format.format(bestNewAxiom.get().getAccuracy());
301                                                        }
302                                                }
303                                        }
304                                }
305                                logger.info(s);
306                        }
307                }
308        }
309
310        /**
311         * Compute the popularity of the entity to describe. This depends on the axiom type, thus, the mehtod might
312         * be overwritten in the corresponding algorithm classes.
313         * @return the populairty of the entity to describe
314         */
315        protected int getPopularity() {
316                return reasoner.getPopularity(entityToDescribe);
317        }
318        
319        private void generateSample(){
320                logger.info("Generating sample...");
321                sample = ModelFactory.createDefaultModel();
322                
323                // we have to set up a new query execution factory working on our local model
324                qef = new QueryExecutionFactoryModel(sample);
325                reasoner = new SPARQLReasoner(qef);
326                
327                // get the page size
328                //TODO put to base class
329                long pageSize = 10000;//PaginationUtils.adjustPageSize(globalQef, 10000);
330                
331                ParameterizedSparqlString sampleQueryTemplate = getSampleQuery();
332                sampleQueryTemplate.setIri("p", entityToDescribe.toStringID());
333                Query query = sampleQueryTemplate.asQuery();
334                query.setLimit(pageSize);
335                
336                boolean isEmpty = false;
337                int i = 0;
338                while(!isTimeout() && !isEmpty){
339                        // get next sample
340                        logger.debug("Extending sample...");
341                        query.setOffset(i++ * pageSize);
342                        QueryExecution qe = ksQef.createQueryExecution(query);
343                        Model tmp = qe.execConstruct();
344                        sample.add(tmp);
345                        
346                        // if last call returned empty model, we can leave loop
347                        isEmpty = tmp.isEmpty();
348                }
349                logger.info("...done. Sample size: " + sample.size() + " triples");
350        }
351        
352        /**
353         * @param progressMonitor the progressMonitor to set
354         */
355        public void setProgressMonitor(AxiomLearningProgressMonitor progressMonitor) {
356                this.progressMonitor = progressMonitor;
357        }
358
359        @Override
360        public void init() throws ComponentInitException {
361                if(ks.isRemote()){
362                        ksQef = ks.getQueryExecutionFactory();
363                } else {
364                        ksQef = new QueryExecutionFactoryModel(((LocalModelBasedSparqlEndpointKS)ks).getModel());
365                }
366                if(ksReasoner == null){
367                        ksReasoner = new SPARQLReasoner(ksQef);
368                }
369//              ksReasoner.supportsSPARQL1_1();
370                reasoner = ksReasoner;
371                
372                initialized = true;
373        }
374        
375        /**
376         * Compute the defined axioms in the knowledge base.
377         */
378        protected abstract void getExistingAxioms();
379        
380        /**
381         * Learn new OWL axioms based on instance data.
382         */
383        protected abstract void learnAxioms();
384        
385        /**
386         * The SPARQL CONSTRUCT query used to generate a sample for the given axiom type  and entity.
387         * @return the SPARQL query
388         */
389        protected abstract ParameterizedSparqlString getSampleQuery();
390
391        @Override
392        public List<T> getCurrentlyBestAxioms() {
393                return getCurrentlyBestAxioms(Integer.MAX_VALUE);
394        }
395        
396        @Override
397        public List<T> getCurrentlyBestAxioms(int nrOfAxioms) {
398                return getCurrentlyBestAxioms(nrOfAxioms, 0.0);
399        }
400        
401        public boolean wasTimeout() {
402                return timeout;
403        }
404        
405        public boolean isTimeout(){
406                return maxExecutionTimeInSeconds != 0 && getRemainingRuntimeInMilliSeconds() <= 0;
407        }
408        
409        public List<T> getCurrentlyBestAxioms(int nrOfAxioms,
410                        double accuracyThreshold) {
411                return getCurrentlyBestEvaluatedAxioms(nrOfAxioms, accuracyThreshold)
412                                .stream()
413                                .map(EvaluatedAxiom<T>::getAxiom)
414                                .collect(Collectors.toList());
415        }
416        
417        public List<T> getCurrentlyBestAxioms(double accuracyThreshold) {
418                return getCurrentlyBestEvaluatedAxioms(accuracyThreshold)
419                                .stream()
420                                .map(EvaluatedAxiom<T>::getAxiom)
421                                .collect(Collectors.toList());
422        }
423        
424        public EvaluatedAxiom<T> getCurrentlyBestEvaluatedAxiom() {
425                if(currentlyBestAxioms.isEmpty()) {
426                        return null;
427                }
428                return currentlyBestAxioms.last();
429        }
430        
431        @Override
432        public List<EvaluatedAxiom<T>> getCurrentlyBestEvaluatedAxioms() {
433                ArrayList<EvaluatedAxiom<T>> axioms = new ArrayList<>(currentlyBestAxioms);
434
435                // revert because highest element in tree set is last
436                Collections.reverse(axioms);
437
438                return axioms;
439        }
440
441        @Override
442        public List<EvaluatedAxiom<T>> getCurrentlyBestEvaluatedAxioms(int nrOfAxioms) {
443                return getCurrentlyBestEvaluatedAxioms(nrOfAxioms, 0.0);
444        }
445        
446        public List<EvaluatedAxiom<T>> getCurrentlyBestEvaluatedAxioms(double accuracyThreshold) {
447                return getCurrentlyBestEvaluatedAxioms(Integer.MAX_VALUE, accuracyThreshold);
448        }
449
450        @Override
451        public List<EvaluatedAxiom<T>> getCurrentlyBestEvaluatedAxioms(int nrOfAxioms,
452                        double accuracyThreshold) {
453                List<EvaluatedAxiom<T>> returnList = new ArrayList<>();
454                
455                //get the currently best evaluated axioms
456                List<EvaluatedAxiom<T>> currentlyBestEvAxioms = getCurrentlyBestEvaluatedAxioms();
457
458                for(EvaluatedAxiom<T> evAx : currentlyBestEvAxioms){
459                        if(evAx.getScore().getAccuracy() >= accuracyThreshold && returnList.size() < nrOfAxioms){
460                                if(returnOnlyNewAxioms){
461                                        if(!existingAxioms.contains(evAx.getAxiom())){
462                                                returnList.add(evAx);
463                                        }
464                                } else {
465                                        returnList.add(evAx);
466                                }
467                        }
468                }
469                
470                return returnList;
471        }
472        
473        public EvaluatedAxiom<T> getBestEvaluatedAxiom(){
474                if(!currentlyBestAxioms.isEmpty()){
475                        return new TreeSet<>(currentlyBestAxioms).last();
476                }
477                return null;
478        }
479        
480        protected Set<OWLClass> getAllClasses() {
481                if(ks.isRemote()){
482                        return new SPARQLTasks(ks.getEndpoint()).getAllClasses();
483                } else {
484                        return ((LocalModelBasedSparqlEndpointKS) ks).getModel().listClasses()
485                                        .filterDrop(new OWLFilter())
486                                        .filterDrop(new RDFSFilter())
487                                        .filterDrop(new RDFFilter())
488                                        .toList().stream()
489                                        .filter(cls -> !cls.isAnon())
490                                        .map(cls -> df.getOWLClass(IRI.create(cls.getURI())))
491                                        .collect(Collectors.toCollection(TreeSet::new));
492                }
493                
494        }
495        
496        protected Model executeConstructQuery(String query) {
497                logger.trace("Sending query\n{} ...", query);
498                QueryExecution qe = qef.createQueryExecution(query);
499                try {
500                        Model model = qe.execConstruct();
501                        timeout = false;
502                        if(model.size() == 0){
503                                fullDataLoaded = true;
504                        }
505                        logger.debug("Got " + model.size() + " triples.");
506                        return model;
507                } catch (QueryExceptionHTTP e) {
508                        if(e.getCause() instanceof SocketTimeoutException){
509                                logger.warn("Got timeout");
510                        } else {
511                                logger.error("Exception executing query", e);
512                        }
513                        return ModelFactory.createDefaultModel();
514                }
515        }
516        
517        protected ResultSet executeSelectQuery(String query) {
518                logger.trace("Sending query\n{} ...", query);
519                
520                QueryExecution qe = qef.createQueryExecution(query);
521                try {
522                        ResultSet rs = qe.execSelect();
523                        timeout = false;
524                        return rs;
525                } catch (QueryExceptionHTTP e) {
526                        if(e.getCause() instanceof SocketTimeoutException){
527                                if(timeout){
528                                        logger.warn("Got timeout");
529                                        throw e;
530                                } else {
531                                        logger.trace("Got local timeout");
532                                }
533                                
534                        } else {
535                                logger.error("Exception executing query", e);
536                        }
537                        return new ResultSetMem();
538                }
539        }
540        
541        protected ResultSet executeSelectQuery(String query, Model model) {
542                logger.trace("Sending query on local model\n{} ...", query);
543                QueryExecutionFactory qef = new QueryExecutionFactoryModel(model);
544                QueryExecution qexec = qef.createQueryExecution(query);
545                return qexec.execSelect();
546        }
547        
548        protected boolean executeAskQuery(String query){
549                logger.trace("Sending query\n{} ...", query);
550                return qef.createQueryExecution(query).execAsk();
551        }
552        
553        protected <K, V extends Comparable<V>> List<Entry<K, V>> sortByValues(Map<K, V> map){
554                List<Entry<K, V>> entries = new ArrayList<>(map.entrySet());
555        Collections.sort(entries, (o1, o2) -> o2.getValue().compareTo(o1.getValue()));
556        return entries;
557        }
558        
559        protected long getRemainingRuntimeInMilliSeconds(){
560                return Math.max(0, (maxExecutionTimeInSeconds * 1000) - (System.currentTimeMillis() - startTime));
561        }
562        
563        protected boolean terminationCriteriaSatisfied(){
564                return maxExecutionTimeInSeconds != 0 && getRemainingRuntimeInMilliSeconds() <= 0;
565        }
566        
567        protected List<Entry<OWLClassExpression, Integer>> sortByValues(Map<OWLClassExpression, Integer> map, final boolean useHierachy){
568                List<Entry<OWLClassExpression, Integer>> entries = new ArrayList<>(map.entrySet());
569                final ClassHierarchy hierarchy = reasoner.getClassHierarchy();
570                
571        Collections.sort(entries, (o1, o2) -> {
572                int ret = o2.getValue().compareTo(o1.getValue());
573                //if the score is the same, than we optionally also take into account the subsumption hierarchy
574                if(ret == 0 && useHierachy){
575                        if(hierarchy != null){
576                                if(hierarchy.contains(o1.getKey()) && hierarchy.contains(o2.getKey())){
577                                        if(hierarchy.isSubclassOf(o1.getKey(), o2.getKey())){
578                                                ret = -1;
579                                        } else if(hierarchy.isSubclassOf(o2.getKey(), o1.getKey())){
580                                                ret = 1;
581                                        } else {
582                                                //we use the depth in the class hierarchy as third ranking property
583//                                                              int depth1 = hierarchy.getDepth2Root(o1.getKey());
584//                                                              int depth2 = hierarchy.getDepth2Root(o2.getKey());
585//                                                              ret = depth1 - depth2;
586                                        }
587                                }
588                        }
589                }
590
591                return ret;
592        });
593        return entries;
594        }
595        
596        protected AxiomScore computeScore(int total, int success){
597                return computeScore(total, success, false);
598        }
599        
600        protected AxiomScore computeScore(int total, int success, boolean sample){
601                if(success > total){
602                        logger.warn("success value > total value");
603                }
604                double[] confidenceInterval = Heuristics.getConfidenceInterval95Wald(total, success);
605                
606                double accuracy = Heuristics.getConfidenceInterval95WaldAverage(total, success);
607        
608                double confidence = confidenceInterval[1] - confidenceInterval[0];
609                
610                return new AxiomScore(accuracy, confidence, success, total-success, sample);
611        }
612//
613//      protected double accuracy(int total, int success){
614//              double[] confidenceInterval = Heuristics.getConfidenceInterval95Wald(total, success);
615//              return (confidenceInterval[0] + confidenceInterval[1]) / 2;
616//      }
617//
618//      protected double fMEasure(double precision, double recall){
619//              return 2 * precision * recall / (precision + recall);
620//      }
621        
622        
623        public void addFilterNamespace(String namespace){
624                allowedNamespaces.add(namespace);
625        }
626        
627        @SuppressWarnings("unchecked")
628        public Set<S> getPositiveExamples(EvaluatedAxiom<T> evAxiom) {
629                return getExamples(posExamplesQueryTemplate, evAxiom);
630        }
631
632        @SuppressWarnings("unchecked")
633        public Set<S> getNegativeExamples(EvaluatedAxiom<T> evAxiom) {
634                return getExamples(negExamplesQueryTemplate, evAxiom);
635        }
636
637        @SuppressWarnings("unchecked")
638        protected Set<S> getExamples(ParameterizedSparqlString queryTemplate, EvaluatedAxiom<T> evAxiom) {
639                ResultSet rs = executeSelectQuery(queryTemplate.toString());
640
641                Set<OWLObject> negExamples = new TreeSet<>();
642
643                while(rs.hasNext()){
644                        RDFNode node = rs.next().get("s");
645                        if(node.isResource()){
646                                negExamples.add(df.getOWLNamedIndividual(IRI.create(node.asResource().getURI())));
647                        } else if(node.isLiteral()){
648                                negExamples.add(convertLiteral(node.asLiteral()));
649                        }
650                }
651                return (Set<S>) negExamples;
652        }
653        
654        public void explainScore(EvaluatedAxiom<T> evAxiom){
655                AxiomScore score = evAxiom.getScore();
656                int posExampleCnt = score.getNrOfPositiveExamples();
657                int negExampleCnt = score.getNrOfNegativeExamples();
658                int total = posExampleCnt + negExampleCnt;
659                StringBuilder sb = new StringBuilder();
660                String lb = "\n";
661                sb.append("######################################").append(lb);
662                sb.append("Explanation:").append(lb);
663                sb.append("Score(").append(evAxiom.getAxiom()).append(") = ").append(evAxiom.getScore().getAccuracy()).append(lb);
664                sb.append("Total number of resources:\t").append(total).append(lb);
665                sb.append("Number of positive examples:\t").append(posExampleCnt).append(lb);
666                sb.append("Number of negative examples:\t").append(negExampleCnt).append(lb);
667                sb.append("Based on sample:            \t").append(score.isSampleBased()).append(lb);
668                if(sample != null){
669                        sb.append("Sample size(#triples):      \t").append(sample.size()).append(lb);
670                }
671                sb.append("######################################");
672                System.out.println(sb.toString());
673        }
674
675        public long getEvaluatedFramentSize(){
676                return sample.size();
677        }
678        
679        /**
680         * Converts a JENA API Literal object into an OWL API OWLLiteral object.
681         * 
682         * @param lit the JENA API literal
683         * @return the OWL API literal
684         */
685        protected OWLLiteral convertLiteral(Literal lit) {
686                String datatypeURI = lit.getDatatypeURI();
687                OWLLiteral owlLiteral;
688                if (datatypeURI == null) {// rdf:PlainLiteral
689                        owlLiteral = df.getOWLLiteral(lit.getLexicalForm(), lit.getLanguage());
690                } else {
691                        owlLiteral = df.getOWLLiteral(lit.getLexicalForm(), df.getOWLDatatype(IRI.create(datatypeURI)));
692                }
693                return owlLiteral;
694        }
695        
696        public static <E> void printSubset(Collection<E> collection, int maxSize){
697                StringBuilder sb = new StringBuilder();
698                int i = 0;
699                Iterator<E> iter = collection.iterator();
700                while(iter.hasNext() && i < maxSize){
701                        sb.append(iter.next().toString()).append(", ");
702                        i++;
703                }
704                if(iter.hasNext()){
705                        sb.append("...(").append(collection.size()-i).append(" more)");
706                }
707                System.out.println(sb.toString());
708        }
709        
710        protected <K,J extends Set<V>, V> void addToMap(Map<K, J> map, K key, V value ){
711                J values = map.get(key);
712                if(values == null){
713                        try {
714                                values = (J) value.getClass().newInstance();
715                                values.add(value);
716                        }
717                        catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();return;}
718                }
719                values.add(value);
720        }
721        
722        protected <K,J extends Set<V>, V> void addToMap(Map<K, J> map, K key, Collection<V> newValues ){
723                J values = map.get(key);
724                if(values == null){
725                        try {
726                                values = (J) newValues.getClass().newInstance();
727                        } catch (InstantiationException | IllegalAccessException e) {
728                                e.printStackTrace();
729                        }
730                        map.put(key, values);
731                }
732                values.addAll(newValues);
733        }
734        
735        @Autowired
736        public void setKs(SparqlEndpointKS ks) {
737                this.ks = ks;
738        }
739        
740        class OWLFilter implements Predicate<OntClass> {
741
742                @Override
743                public boolean test(OntClass cls) {
744                        if(!cls.isAnon()){
745                                return cls.getURI().startsWith(OWL2.getURI());
746                        }
747                        return false;
748                }
749        }
750        
751        class RDFSFilter implements Predicate<OntClass>{
752
753                @Override
754                public boolean test(OntClass cls) {
755                        if(!cls.isAnon()){
756                                return cls.getURI().startsWith(RDFS.getURI());
757                        }
758                        return false;
759                }
760                
761        }
762        
763        class RDFFilter implements Predicate<OntClass>{
764
765                @Override
766                public boolean test(OntClass cls) {
767                        if(!cls.isAnon()){
768                                return cls.getURI().startsWith(RDF.getURI());
769                        }
770                        return false;
771                }
772                
773        }
774        
775
776}