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.utilities.examples;
020
021import java.util.Collection;
022import java.util.SortedSet;
023import java.util.TreeSet;
024
025import org.apache.log4j.Logger;
026import org.dllearner.core.AbstractReasonerComponent;
027import org.dllearner.utilities.datastructures.SetManipulation;
028import org.semanticweb.owlapi.model.OWLClass;
029import org.semanticweb.owlapi.model.OWLClassExpression;
030import org.semanticweb.owlapi.model.OWLIndividual;
031import org.semanticweb.owlapi.model.OWLObjectProperty;
032
033public class AutomaticNegativeExampleFinderOWL {
034
035        // LOGGER
036        private static Logger logger = Logger.getLogger(AutomaticNegativeExampleFinderOWL.class);
037
038        private AbstractReasonerComponent reasoningService;
039        
040        private SortedSet<OWLIndividual> fullPositiveSet;
041
042        private SortedSet<OWLIndividual> fromRelated  = new TreeSet<>();
043        private SortedSet<OWLIndividual> fromSuperclasses = new TreeSet<>();
044        private SortedSet<OWLIndividual> fromParallelClasses = new TreeSet<>();
045        private SortedSet<OWLIndividual> fromAllOther = new TreeSet<>();
046        private SortedSet<OWLIndividual> fromDomain = new TreeSet<>();
047        private SortedSet<OWLIndividual> fromRange = new TreeSet<>();
048        
049        static int poslimit = 10;
050        static int neglimit = 20;
051
052
053        /**
054         * 
055         * takes as input a full positive set to make sure no negatives are added as positives
056         * 
057         * @param fullPositiveSet
058         * @param reasoningService
059         */
060        public AutomaticNegativeExampleFinderOWL(
061                        SortedSet<OWLIndividual> fullPositiveSet,
062                        AbstractReasonerComponent reasoningService) {
063                super();
064                this.fullPositiveSet = new TreeSet<>();
065                this.fullPositiveSet.addAll(fullPositiveSet);
066                this.reasoningService = reasoningService;
067
068        }
069        
070        /**
071         * see <code>  getNegativeExamples(int neglimit, boolean stable )</code>
072         * @param neglimit
073         */
074        public SortedSet<OWLIndividual> getNegativeExamples(int neglimit, boolean forceNegLimit ) {
075                return getNegativeExamples(neglimit, false, forceNegLimit);
076        }
077
078        /**
079         * aggregates all collected neg examples
080         * CAVE: it is necessary to call one of the make functions before calling this
081         * OTHERWISE it will choose random examples
082         * 
083         * @param neglimit size of negative Example set, 0 means all, which can be quite large
084         * @param stable decides whether neg Examples are randomly picked, default false, faster for developing, since the cache can be used
085         * @param forceNegLimit forces that exactly neglimit instances are returned by adding more instances
086         */
087        public SortedSet<OWLIndividual> getNegativeExamples(int neglimit, boolean stable, boolean forceNegLimit ) {
088                SortedSet<OWLIndividual> negatives = new TreeSet<>();
089                negatives.addAll(fromParallelClasses);
090                negatives.addAll(fromRelated);
091                negatives.addAll(fromSuperclasses);
092                if(negatives.size()< neglimit){
093                        makeNegativeExamplesFromAllOtherInstances();
094                        
095                        negatives.addAll(SetManipulation.stableShrinkInd(fromAllOther, neglimit-negatives.size()));
096                }
097                
098                
099                
100                if(neglimit<=0){
101                        logger.debug("neg Example size NO shrinking: " + negatives.size());
102                        return negatives;
103                }
104                
105                
106                logger.debug("neg Example size before shrinking: " + negatives.size());
107                if (stable ) {
108                        negatives = SetManipulation.stableShrinkInd(negatives,neglimit);
109                }
110                else {
111                        negatives = SetManipulation.fuzzyShrinkInd(negatives,neglimit);
112                }
113                logger.debug("neg Example size after shrinking: " + negatives.size());
114                return negatives;
115        }
116
117        
118        /**
119         * just takes all other instances from the ontology, except the ones 
120         * in the fullPositiveSet (see Constructor)
121         */
122        public void makeNegativeExamplesFromAllOtherInstances() {
123                logger.debug("making random examples ");
124                fromAllOther.clear();
125                fromAllOther.addAll(reasoningService.getIndividuals());
126                fromAllOther.removeAll(fullPositiveSet);
127                logger.debug("|-negExample size from random: " + fromAllOther.size());
128        }
129        
130        /**
131         * NOT IMPLEMENTED YET, DO NOT USE
132         * makes neg ex from related instances, that take part in a role R(pos,neg)
133         * filters all objects, that don't use the given namespace 
134         * @param instances
135         * @param objectNamespace
136         */
137        public void makeNegativeExamplesFromRelatedInstances(SortedSet<OWLIndividual> instances,
138                        String objectNamespace) {
139                logger.debug("making examples from related instances");
140                for (OWLIndividual oneInstance : instances) {
141                        makeNegativeExamplesFromRelatedInstances(oneInstance, objectNamespace);
142                }
143                logger.debug("|-negExample size from related: " + fromRelated.size());
144        }
145
146        /**
147         * NOT IMPLEMENTED YET, DO NOT USE
148         * @param oneInstance
149         * @param objectnamespace
150         */
151        private void makeNegativeExamplesFromRelatedInstances(OWLIndividual oneInstance, String objectnamespace) {
152                // SortedSet<String> result = new TreeSet<String>();
153
154                //reasoningService.getRoleMembers(atomicRole)
155                
156                //fromRelated.removeAll(fullPositiveSet);
157                throw new RuntimeException("method makeNegativeExamplesFromRelatedInstances not implemented yet");
158        }
159
160
161        
162        /**
163         * NOT IMPLEMENTED YET, DO NOT USE
164         * makes negEx from classes, the posEx belong to.
165         * Gets all Classes from PosEx, gets Instances from these Classes, returns all
166         * @param positiveSet
167         */
168        public void makeNegativeExamplesFromParallelClasses(SortedSet<OWLIndividual> positiveSet){
169                makeNegativeExamplesFromClassesOfInstances(positiveSet);
170        }
171        
172        /**
173         * NOT IMPLEMENTED YET, DO NOT USE
174         * see <code> makeNegativeExamplesFromParallelClasses</code>
175         * @param positiveSet
176         */
177        @SuppressWarnings("unused")
178        private void makeNegativeExamplesFromClassesOfInstances(SortedSet<OWLIndividual> positiveSet) {
179                logger.debug("making neg Examples from parallel classes");
180                SortedSet<OWLClassExpression> classes = new TreeSet<>();
181                this.fromParallelClasses.clear();
182                
183                for (OWLIndividual instance : positiveSet) {
184                        try{
185                        // realization is not implemented in reasoningservice
186                        //classes.addAll(reasoningService.realize()
187                        }catch (Exception e) {
188                                logger.warn("not implemented in "+this.getClass());
189                        }
190                }
191                logger.debug("getting negExamples from " + classes.size() + " parallel classes");
192                for (OWLClassExpression oneClass : classes) {
193                        logger.debug(oneClass);
194                        // rsc = new
195                        // JenaResultSetConvenience(queryConcept("\""+oneClass+"\"",limit));
196                        try{
197                        this.fromParallelClasses.addAll(reasoningService.getIndividuals(oneClass));
198                        }catch (Exception e) {
199                                logger.warn("not implemented in "+this.getClass());
200                        }
201                }
202                
203                fromParallelClasses.removeAll(fullPositiveSet);
204                logger.debug("|-neg Example size from parallelclass: " + fromParallelClasses.size());
205                throw new RuntimeException("not implemented in "+ this.getClass()+"method makeNegativeExamplesFromParallelClasses");
206        }
207
208        
209        
210        
211        
212        /**
213         * if pos ex derive from one class, then neg ex are taken from a superclass
214         * @param concept
215         */
216        public void makeNegativeExamplesFromSuperClasses(OWLClass concept) {
217                makeNegativeExamplesFromSuperClasses( concept, 0);
218        }
219        
220        /**
221         * if pos ex derive from one class, then neg ex are taken from a superclass
222         * CURRENTLY SAME METHOD AS makeNegativeExamplesFromSuperClasses(OWLClass concept)
223         * but works quite often 
224         * @param concept
225         * @param depth PARAMETER CURRENTLY NOT USED, ONLY DIRECT SUPERCLASSES
226         */
227        public void makeNegativeExamplesFromSuperClasses(OWLClass concept, int depth) {
228
229                fromSuperclasses.clear();
230                SortedSet<OWLClassExpression> superClasses = reasoningService.getSuperClasses(concept);
231                logger.debug("making neg Examples from " + superClasses.size() + " superclasses");
232
233                for (OWLClassExpression oneSuperClass : superClasses) {
234                        logger.debug(oneSuperClass);
235                        fromSuperclasses.addAll(reasoningService.getIndividuals(oneSuperClass));
236                }
237                this.fromSuperclasses.removeAll(fullPositiveSet);
238                logger.debug("|-neg Example from superclass: " + fromSuperclasses.size());
239        }
240        
241        /**
242         * misleading method name,
243         * examples are all instances from the a-Part of the atomicRole(a,b)
244         * it has nothing to do with the actual Domain class 
245         * @param atomicRole
246         */
247        
248        public void makeNegativeExamplesFromDomain(OWLObjectProperty atomicRole){
249                fromDomain.clear();
250                logger.debug("making Negative Examples from Domain of : "+atomicRole);
251                fromDomain.addAll(reasoningService.getPropertyMembers(atomicRole).keySet());
252                fromDomain.removeAll(fullPositiveSet);
253                logger.debug("|-neg Example size from Domain: "+this.fromDomain.size());
254        }
255        
256        /**
257         * misleading method name,
258         * examples are all instances from the b-Part of the atomicRole(a,b)
259         * it has nothing to do with the actual Range class 
260         * @param atomicRole
261         */
262
263        public void makeNegativeExamplesFromRange(OWLObjectProperty atomicRole){
264                fromRange.clear();
265                logger.debug("making Negative Examples from Range of : "+atomicRole);
266                Collection<SortedSet<OWLIndividual>> tmp = reasoningService.getPropertyMembers(atomicRole).values();
267                for (SortedSet<OWLIndividual> set : tmp) {
268                        fromRange.addAll(set);
269                }
270                fromRange.removeAll(fullPositiveSet);
271                logger.debug("|-neg Example size from Range: "+fromRange.size());
272        }
273}