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.refinementoperators;
021    
022    import java.util.HashSet;
023    import java.util.Iterator;
024    import java.util.LinkedList;
025    import java.util.List;
026    import java.util.Set;
027    import java.util.TreeSet;
028    
029    import org.dllearner.core.AbstractReasonerComponent;
030    import org.dllearner.core.owl.ObjectAllRestriction;
031    import org.dllearner.core.owl.NamedClass;
032    import org.dllearner.core.owl.Nothing;
033    import org.dllearner.core.owl.Description;
034    import org.dllearner.core.owl.ObjectSomeRestriction;
035    import org.dllearner.core.owl.Intersection;
036    import org.dllearner.core.owl.Union;
037    import org.dllearner.core.owl.Negation;
038    import org.dllearner.core.owl.ObjectProperty;
039    import org.dllearner.core.owl.ObjectQuantorRestriction;
040    import org.dllearner.core.owl.Thing;
041    import org.dllearner.learningproblems.PosNegLP;
042    import org.dllearner.utilities.owl.ConceptComparator;
043    
044    public class PsiUp extends RefinementOperatorAdapter {
045    
046            ConceptComparator conceptComparator = new ConceptComparator();
047            
048            PosNegLP learningProblem;
049            AbstractReasonerComponent reasoningService;
050            
051            private TreeSet<Description> bottomSet;
052            
053            public PsiUp(PosNegLP learningProblem, AbstractReasonerComponent reasoningService) {
054                    this.learningProblem = learningProblem;
055                    this.reasoningService = reasoningService;
056                    
057                    // Top-Menge erstellen
058                    createBottomSet();
059            }
060            
061            private void createBottomSet() {
062                    bottomSet = new TreeSet<Description>(conceptComparator);
063                    
064                    // BOTTOM AND BOTTOM
065                    Intersection mc = new Intersection();
066                    mc.addChild(new Nothing());
067                    mc.addChild(new Nothing());
068                    bottomSet.add(mc);
069                    
070                    // speziellste Konzepte
071                    bottomSet.addAll(reasoningService.getSuperClasses(new Nothing()));
072                    
073                    // negierte allgemeinste Konzepte
074                    Set<Description> tmp = reasoningService.getSubClasses(new Thing());
075                    for(Description c : tmp) 
076                            bottomSet.add(new Negation(c));
077            
078                    // EXISTS r.BOTTOM und ALL r.BOTTOM für alle r
079                    for(ObjectProperty r : reasoningService.getObjectProperties()) {
080                            bottomSet.add(new ObjectAllRestriction(r, new Nothing()));
081                            bottomSet.add(new ObjectSomeRestriction(r, new Nothing()));
082                    }
083            }
084            
085            @Override
086            @SuppressWarnings("unchecked")
087            public Set<Description> refine(Description concept) {
088                    
089                    Set<Description> refinements = new HashSet<Description>();
090                    Set<Description> tmp = new HashSet<Description>();
091                    
092                    if (concept instanceof Thing) {
093                            return new TreeSet<Description>(conceptComparator);
094                    } else if (concept instanceof Nothing) {
095                            return (Set<Description>) bottomSet.clone();                      
096                    } else if (concept instanceof NamedClass) {
097                            // Top darf hier mit dabei sein
098                            refinements.addAll(reasoningService.getSuperClasses(concept));
099                            
100                    // negiertes atomares Konzept
101                    } else if (concept instanceof Negation && concept.getChild(0) instanceof NamedClass) {
102                            tmp.addAll(reasoningService.getSubClasses(concept.getChild(0)));
103                            
104                            // Bottom rausschmeissen
105                            boolean containsBottom = false;
106                            Iterator<Description> it = tmp.iterator();
107                            while(it.hasNext()) {
108                                    Description c = it.next();
109                                    if(c instanceof Nothing) {
110                                            it.remove();
111                                            containsBottom = true;
112                                    }
113                            }
114                            // es soll z.B. NOT male auch zu NOT BOTTOM d.h. zu TOP verfeinert
115                            // werden können
116                            if(containsBottom)
117                                    refinements.add(new Thing());
118                            
119                            for(Description c : tmp) {
120                                    refinements.add(new Negation(c));
121                            }
122                    } else if (concept instanceof Intersection) {
123                            // eines der Elemente kann verfeinert werden
124                            for(Description child : concept.getChildren()) {
125                                    
126                                    // Refinement für das Kind ausführen
127                                    tmp = refine(child);
128                                    
129                                    // neue MultiConjunction konstruieren
130                                    for(Description c : tmp) {
131                                            // TODO: müssen auch alle Konzepte geklont werden??
132                                            // hier wird nur eine neue Liste erstellt
133                                            // => eigentlich muss nicht geklont werden (d.h. deep copy) da
134                                            // die Konzepte nicht verändert werden während des Algorithmus
135                                            List<Description> newChildren = new LinkedList<Description>(concept.getChildren());
136                                            // es muss genau die vorherige Reihenfolge erhalten bleiben
137                                            // (zumindest bis die Normalform definiert ist)
138                                            int index = newChildren.indexOf(child);
139                                            newChildren.add(index, c);                                      
140                                            newChildren.remove(child);
141                                            Intersection mc = new Intersection(newChildren);
142                                            refinements.add(mc);    
143                                    }
144                            }
145                            
146                            // ein Element der Konjunktion kann weggelassen werden
147                            for(Description child : concept.getChildren()) {
148                                    List<Description> newChildren = new LinkedList<Description>(concept.getChildren());
149                                    newChildren.remove(child);
150                                    if(newChildren.size()==1)
151                                            refinements.add(newChildren.get(0));
152                                    else {
153                                            Intersection md = new Intersection(newChildren);
154                                            refinements.add(md);
155                                    }
156                            }                       
157                    } else if (concept instanceof Union) {
158                            // eines der Elemente kann verfeinert werden
159                            for(Description child : concept.getChildren()) {
160                                    
161                                    // Refinement für das Kind ausführen
162                                    // tmp = refine(child);
163                                    tmp = refine(child);
164                                    // neue MultiConjunction konstruieren
165                                    for(Description c : tmp) {
166                                            List<Description> newChildren = new LinkedList<Description>(concept.getChildren());
167                                            // es muss genau die vorherige Reihenfolge erhalten bleiben
168                                            // (zumindest bis die Normalform definiert ist)
169                                            int index = newChildren.indexOf(child);
170                                            newChildren.add(index, c);                                      
171                                            newChildren.remove(child);                                      
172                                            Union md = new Union(newChildren);
173                                            refinements.add(md);    
174                                    }
175                            }
176                    } else if (concept instanceof ObjectSomeRestriction) {
177                            tmp = refine(concept.getChild(0));
178                            for(Description c : tmp) {
179                                    refinements.add(new ObjectSomeRestriction(((ObjectQuantorRestriction)concept).getRole(),c));
180                            }               
181                            
182                            if(concept.getChild(0) instanceof Thing)
183                                    refinements.add(new Thing());
184                            
185                    } else if (concept instanceof ObjectAllRestriction) {
186                            tmp = refine(concept.getChild(0));
187                            for(Description c : tmp) {
188                                    refinements.add(new ObjectAllRestriction(((ObjectQuantorRestriction)concept).getRole(),c));
189                            }               
190                            
191                            if(concept.getChild(0) instanceof Thing)
192                                    refinements.add(new Thing());                   
193                            
194                            // falls es keine spezielleren atomaren Konzepte gibt, dann wird 
195                            // bottom angehangen => nur wenn es ein atomares Konzept (insbesondere != bottom)
196                            // ist
197                            // if(tmp.size()==0) {
198                            // if(concept.getChild(0) instanceof AtomicConcept && tmp.size()==0) {
199                            //      refinements.add(new All(((Quantification)concept).getRole(),new Bottom()));
200                            //}
201                    } else
202                            throw new RuntimeException(concept.toString());
203                    
204                    if(concept instanceof Union || concept instanceof NamedClass ||
205                                    concept instanceof Negation || concept instanceof ObjectSomeRestriction || concept instanceof ObjectAllRestriction) {
206                            
207                            // es wird OR BOTTOM angehangen
208                            Union md = new Union();
209                            md.addChild(concept);
210                            md.addChild(new Nothing());                                     
211                            refinements.add(md);
212                    }
213    
214                    // Refinements werden jetzt noch bereinigt, d.h. Verschachtelungen von Konjunktionen
215                    // werden entfernt; es wird eine neue Menge erzeugt, da die Transformationen die
216                    // Ordnung des Konzepts ändern könnten
217                    // TODO: eventuell geht das noch effizienter, da die meisten Refinement-Regeln Refinements
218                    // von Child-Konzepten sind, die bereits geordnet sind, d.h. man könnte dort eventuell
219                    // gleich absichern, dass alle neu hinzugefügten Refinements in geordneter Negationsnormalform
220                    // sind
221                    // SortedSet<Concept> returnSet = new TreeSet<Concept>(conceptComparator);
222                    /*
223                    Set<Concept> returnSet = new HashSet<Concept>();
224                    for(Concept c : refinements) {
225                            ConceptTransformation.cleanConcept(c);
226                            // ConceptTransformation.transformToOrderedNegationNormalForm(c, conceptComparator);
227                            returnSet.add(c);
228                    }
229                    
230                    return returnSet;
231                    */
232                    return refinements;
233            }
234    
235            @Override
236            public Set<Description> refine(Description concept, int maxLength,
237                            List<Description> knownRefinements) {
238                    throw new RuntimeException();
239            }
240    
241    }