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.properties;
020
021import org.dllearner.core.AbstractAxiomLearningAlgorithm;
022import org.dllearner.core.config.ConfigOption;
023import org.dllearner.learningproblems.AxiomScore;
024import org.dllearner.learningproblems.Heuristics;
025import org.semanticweb.owlapi.model.OWLLogicalAxiom;
026import org.semanticweb.owlapi.model.OWLObject;
027import org.semanticweb.owlapi.model.OWLProperty;
028
029import org.apache.jena.query.ParameterizedSparqlString;
030import org.apache.jena.query.ResultSet;
031import org.apache.jena.rdf.model.Model;
032
033/**
034 * A learning algorithm for property axioms. 
035 * @author Lorenz Buehmann
036 *
037 */
038public abstract class PropertyAxiomLearner<S extends OWLProperty, T extends OWLLogicalAxiom, V extends OWLObject> extends AbstractAxiomLearningAlgorithm<T, V, S>{
039        
040        protected static final ParameterizedSparqlString TRIPLES_COUNT_QUERY = new ParameterizedSparqlString(
041                        "SELECT (COUNT(*) as ?cnt) WHERE {?s ?p ?o .}");
042        
043        protected static final ParameterizedSparqlString DISTINCT_SUBJECTS_COUNT_QUERY = new ParameterizedSparqlString(
044                        "SELECT (COUNT(DISTINCT(?s)) as ?cnt) WHERE {?s ?p ?o .}");
045        
046        protected static final ParameterizedSparqlString DISTINCT_OBJECTS_COUNT_QUERY = new ParameterizedSparqlString(
047                        "SELECT (COUNT(DISTINCT(?o)) as ?cnt) WHERE {?s ?p ?o .}");
048        
049        protected static final ParameterizedSparqlString GET_SAMPLE_QUERY = new ParameterizedSparqlString(
050                        "CONSTRUCT {?s ?p ?o.} WHERE {?s ?p ?o}");
051        
052        protected ParameterizedSparqlString COUNT_QUERY = TRIPLES_COUNT_QUERY;
053
054        @ConfigOption(defaultValue = "true", description = "make SPARQL OWL queries a bit more strict (currently: also test " +
055                        "if a class is an owl:Class in some cases)")
056        protected boolean strictOWLMode = true;
057
058        // a property domain axiom can formally be seen as a subclass axiom \exists r.\top \sqsubseteq \C
059        // so we have to focus more on accuracy, which we can regulate via the parameter beta
060        double beta = 3.0;
061
062        private boolean useSimpleScore = true;
063        
064        
065        /* (non-Javadoc)
066         * @see org.dllearner.core.AbstractAxiomLearningAlgorithm#setEntityToDescribe(org.semanticweb.owlapi.model.OWLEntity)
067         */
068        @Override
069        public void setEntityToDescribe(S entityToDescribe) {
070                super.setEntityToDescribe(entityToDescribe);
071                
072                posExamplesQueryTemplate.setIri("p", entityToDescribe.toStringID());
073                negExamplesQueryTemplate.setIri("p", entityToDescribe.toStringID());
074                
075                COUNT_QUERY.setIri("p", entityToDescribe.toStringID());
076                DISTINCT_SUBJECTS_COUNT_QUERY.setIri("p", entityToDescribe.toStringID());
077                DISTINCT_OBJECTS_COUNT_QUERY.setIri("p", entityToDescribe.toStringID());
078        }
079
080        /**
081         * Declare the property for which axiom(s) will be computed.
082         *
083         * @param property the property
084         */
085        public void setPropertyToDescribe(S property) {
086                setEntityToDescribe(property);
087        }
088        
089        /**
090         * @param strictOWLMode the strictOWLMode to set
091         */
092        public void setStrictOWLMode(boolean strictOWLMode) {
093                this.strictOWLMode = strictOWLMode;
094        }
095        
096        @Override
097        protected ParameterizedSparqlString getSampleQuery(){
098                return GET_SAMPLE_QUERY;
099        }
100        
101        /* (non-Javadoc)
102         * @see org.dllearner.core.AbstractAxiomLearningAlgorithm#learnAxioms()
103         */
104        @Override
105        protected void learnAxioms() {
106                run();
107        }
108        
109        protected int getPropertyPopularity(){
110                return getCountValue(COUNT_QUERY.toString());
111        }
112        
113        protected int getPropertyPopularity(Model model){
114                return getCountValue(COUNT_QUERY.toString(), model);
115        }
116        
117        protected int getDistinctSubjectsFrequency(){
118                return getCountValue(DISTINCT_SUBJECTS_COUNT_QUERY.toString());
119        }
120        
121        protected int getDistinctObjectsFrequency(){
122                return getCountValue(DISTINCT_OBJECTS_COUNT_QUERY.toString());
123        }
124        
125        protected int getCountValue(String query){
126                ResultSet rs = executeSelectQuery(query);
127                return rs.next().getLiteral("cnt").getInt();
128        }
129        
130        /**
131         * Return the integer value of a SPARQL query that just returns a single COUNT value.
132         * It is assumed the the variable of the COUNT value is ?cnt.
133         * @param query the SPARQL query
134         * @param model the model containing the data
135         * @return the count value
136         */
137        protected int getCountValue(String query, Model model){
138                ResultSet rs = executeSelectQuery(query, model);
139                return rs.next().getLiteral("cnt").getInt();
140        }
141
142        /**
143         * Compute the score of the axiom:
144         *
145         * @param cntA |A|
146         * @param cntB |B|
147         * @param cntAB |A AND B|
148         * @return
149         */
150        protected AxiomScore computeScore(int cntA, int cntB, int cntAB) {
151                // precision (A AND B)/B
152                double precision = Heuristics.getConfidenceInterval95WaldAverage(cntB, cntAB);
153
154                // in the simplest case, the precision is our score
155                double score = precision;
156
157                // if enabled consider also recall and use F-score
158                if(!useSimpleScore ) {
159                        // recall (A AND B)/A
160                        double recall = Heuristics.getConfidenceInterval95WaldAverage(cntA, cntAB);
161
162                        // F score
163                        score = Heuristics.getFScore(recall, precision, beta);
164                }
165
166                int nrOfNegExamples = cntA - cntAB;
167
168                return new AxiomScore(score, score, cntAB, nrOfNegExamples, useSampling);
169        }
170
171        /**
172         * Whether to use only Precision or F-Measure.
173         *
174         * @param usePrecisionOnly
175         */
176        public void setUsePrecisionOnly(boolean usePrecisionOnly) {
177                this.useSimpleScore = usePrecisionOnly;
178        }
179
180        protected abstract void run();
181
182}