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