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