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.pattern;
020
021import org.semanticweb.owlapi.model.*;
022import org.semanticweb.owlapi.vocab.OWLFacet;
023import uk.ac.manchester.cs.owl.owlapi.OWLClassImpl;
024import uk.ac.manchester.cs.owl.owlapi.OWLDatatypeImpl;
025import uk.ac.manchester.cs.owl.owlapi.OWLNamedIndividualImpl;
026
027import javax.annotation.Nonnull;
028import java.util.*;
029import java.util.concurrent.atomic.AtomicInteger;
030import java.util.function.Function;
031import java.util.stream.Collectors;
032
033public class OWLClassExpressionRenamer implements OWLClassExpressionVisitor, OWLPropertyExpressionVisitor, OWLIndividualVisitor, OWLDataRangeVisitor, OWLDataVisitor {
034        
035        private static final String NS = "http://dl-learner.org/pattern/";
036
037        /*
038        Some constants here used for abstraction
039         */
040
041        private static final int MIN_INTEGER_VALUE = 0;
042        private static final int MAX_INTEGER_VALUE = 9;
043        private static final double MIN_DOUBLE_VALUE = 0d;
044        private static final double MAX_DOUBLE_VALUE = 9d;
045        private static final float MIN_FLOAT_VALUE = 0f;
046        private static final float MAX_FLOAT_VALUE = 9f;
047
048
049        private OWLDataFactory df;
050        private Map<OWLEntity, OWLEntity> renaming;
051        private OWLObject renamedOWLObject;
052//      private OWLClassExpressionOrderingComparator comparator = new OWLClassExpressionOrderingComparator();
053        private OWLObjectComparator comparator = new OWLObjectComparator();
054        private Queue<String> classVarQueue = new LinkedList<>();
055        private Queue<String> propertyVarQueue = new LinkedList<>();
056        private Queue<String> individualVarQueue = new LinkedList<>();
057        
058        private OWLLiteralRenamer literalRenamer;
059        
060        private boolean normalizeCardinalities = true;
061        private boolean normalizeHasValue = true;
062        private boolean normalizeOneOf = true;
063
064        private AtomicInteger clsCounter = new AtomicInteger(1);
065
066        private boolean multipleClasses = false;
067
068        
069        public OWLClassExpressionRenamer(OWLDataFactory df, Map<OWLEntity, OWLEntity> renaming) {
070                this.df = df;
071                this.renaming = renaming;
072                
073                literalRenamer = new OWLLiteralRenamer(df);
074                
075                reset();
076        }
077
078        public void reset() {
079                classVarQueue = new LinkedList<>();
080                propertyVarQueue = new LinkedList<>();
081                individualVarQueue = new LinkedList<>();
082
083                for(int i = 65; i <= 90; i++){
084                        classVarQueue.add(String.valueOf((char)i));
085                }
086                for(int j = 2; j <=5; j++){
087                        for(int i = 65; i <= 90; i++){
088                                classVarQueue.add(String.valueOf((char)i) + "_" + j);
089                        }
090                }
091                for(int i = 97; i <= 111; i++){
092                        individualVarQueue.add(String.valueOf((char)i));
093                }
094                for(int i = 112; i <= 122; i++){
095                        propertyVarQueue.add(String.valueOf((char)i));
096                }
097        }
098
099        public void setMultipleClasses(boolean multipleClasses) {
100                this.multipleClasses = multipleClasses;
101        }
102
103        public OWLClassExpression rename(OWLClassExpression expr){
104                renamedOWLObject = null;
105                expr.accept(this);
106                return (OWLClassExpression) renamedOWLObject;
107        }
108        
109        @SuppressWarnings("unchecked")
110        public <T extends OWLPropertyExpression> T rename(T expr){
111                renamedOWLObject = null;
112                expr.accept(this);
113                return (T) renamedOWLObject;
114        }
115        
116        public OWLIndividual rename(OWLIndividual ind){
117                renamedOWLObject = null;
118                ind.accept(this);
119                return (OWLIndividual) renamedOWLObject;
120        }
121        
122        public OWLDataRange rename(OWLDataRange range){
123                renamedOWLObject = null;
124                range.accept(this);
125                return (OWLDataRange) renamedOWLObject;
126        }
127        
128        public OWLLiteral rename(OWLLiteral lit){
129                renamedOWLObject = null;
130                renamedOWLObject = literalRenamer.rename(lit);
131                return (OWLLiteral) renamedOWLObject;
132        }
133        
134        @Override
135        public void visit(OWLObjectIntersectionOf desc) {
136                List<OWLClassExpression> operands = desc.getOperandsAsList();
137//              Collections.sort(operands, comparator);
138                Set<OWLClassExpression> renamedOperands = new HashSet<>();//new TreeSet<>(comparator);
139                for(OWLClassExpression expr : operands){
140                        renamedOperands.add(rename(expr));
141                }
142                renamedOWLObject = df.getOWLObjectIntersectionOf(renamedOperands);
143        }
144        
145        @Override
146        public void visit(OWLObjectUnionOf desc) {
147                List<OWLClassExpression> operands = desc.getOperandsAsList();
148                Collections.sort(operands, comparator);
149                SortedSet<OWLClassExpression> renamedOperands = new TreeSet<>(comparator);
150                for(OWLClassExpression expr : operands){
151                        renamedOperands.add(rename(expr));
152                }
153                renamedOWLObject = df.getOWLObjectUnionOf(renamedOperands);
154        }
155        
156        @Override
157        public void visit(OWLDataHasValue desc) {
158                OWLDataPropertyExpression property = desc.getProperty();
159                property = rename(property);
160                OWLLiteral value = desc.getFiller();
161                value = rename(value);
162                renamedOWLObject = df.getOWLDataHasValue(property, value);
163        }
164
165        @Override
166        public void visit(OWLObjectComplementOf desc) {
167                OWLClassExpression operand = desc.getOperand();
168                operand = rename(operand);
169                renamedOWLObject = df.getOWLObjectComplementOf(operand);
170        }
171
172        @Override
173        public void visit(OWLObjectSomeValuesFrom desc) {
174                OWLObjectPropertyExpression property = desc.getProperty();
175                property = rename(property);
176                OWLClassExpression filler = desc.getFiller();
177                filler = rename(filler);
178                renamedOWLObject = df.getOWLObjectSomeValuesFrom(property, filler);
179        }
180
181        @Override
182        public void visit(OWLObjectAllValuesFrom desc) {
183                OWLObjectPropertyExpression property = desc.getProperty();
184                property = rename(property);
185                OWLClassExpression filler = desc.getFiller();
186                filler = rename(filler);
187                renamedOWLObject = df.getOWLObjectAllValuesFrom(property, filler);
188        }
189
190        @Override
191        public void visit(OWLObjectHasValue desc) {
192                OWLObjectPropertyExpression property = desc.getProperty();
193                property = rename(property);
194                OWLIndividual value = desc.getFiller();
195                value = rename(value);
196                renamedOWLObject = df.getOWLObjectHasValue(property, value);
197        }
198
199        @Override
200        public void visit(OWLObjectMinCardinality desc) {
201                OWLObjectPropertyExpression property = desc.getProperty();
202                property = rename(property);
203                OWLClassExpression filler = desc.getFiller();
204                filler = rename(filler);
205                int cardinality = desc.getCardinality();
206                if(normalizeCardinalities){
207                        cardinality = 1;
208                }
209                renamedOWLObject = df.getOWLObjectMinCardinality(cardinality, property, filler);
210        }
211
212        @Override
213        public void visit(OWLObjectExactCardinality desc) {
214                OWLObjectPropertyExpression property = desc.getProperty();
215                property = rename(property);
216                OWLClassExpression filler = desc.getFiller();
217                filler = rename(filler);
218                int cardinality = desc.getCardinality();
219                if(normalizeCardinalities){
220                        cardinality = 1;
221                }
222                renamedOWLObject = df.getOWLObjectExactCardinality(cardinality, property, filler);
223        }
224
225        @Override
226        public void visit(OWLObjectMaxCardinality desc) {
227                OWLObjectPropertyExpression property = desc.getProperty();
228                property = rename(property);
229                OWLClassExpression filler = desc.getFiller();
230                filler = rename(filler);
231                int cardinality = desc.getCardinality();
232                if(normalizeCardinalities){
233                        cardinality = 1;
234                }
235                renamedOWLObject = df.getOWLObjectMaxCardinality(cardinality, property, filler);
236        }
237
238        @Override
239        public void visit(OWLObjectHasSelf desc) {
240                OWLObjectPropertyExpression property = desc.getProperty();
241                property = rename(property);
242                renamedOWLObject = df.getOWLObjectHasSelf(property);
243        }
244
245        @Override
246        public void visit(OWLObjectOneOf desc) {
247                Set<OWLIndividual> individuals = desc.getIndividuals();
248                Set<OWLIndividual> renamedIndividuals = new TreeSet<>();
249                for (OWLIndividual ind : individuals) {
250                        renamedIndividuals.add(rename(ind));
251                }
252                renamedOWLObject = df.getOWLObjectOneOf(renamedIndividuals);
253        }
254
255        @Override
256        public void visit(OWLDataSomeValuesFrom desc) {
257                OWLDataPropertyExpression property = desc.getProperty();
258                property = rename(property);
259                OWLDataRange filler = desc.getFiller();
260                filler = rename(filler);
261                renamedOWLObject = df.getOWLDataSomeValuesFrom(property, filler);
262        }
263
264        @Override
265        public void visit(OWLDataAllValuesFrom desc) {
266                OWLDataPropertyExpression property = desc.getProperty();
267                property = rename(property);
268                OWLDataRange filler = desc.getFiller();
269                filler = rename(filler);
270                renamedOWLObject = df.getOWLDataAllValuesFrom(property, filler);
271        }
272
273        @Override
274        public void visit(OWLDataMinCardinality desc) {
275                OWLDataPropertyExpression property = desc.getProperty();
276                property = rename(property);
277                OWLDataRange filler = desc.getFiller();
278                filler = rename(filler);
279                int cardinality = desc.getCardinality();
280                if(normalizeCardinalities){
281                        cardinality = 1;
282                }
283                renamedOWLObject = df.getOWLDataMinCardinality(cardinality, property, filler);
284        }
285
286        @Override
287        public void visit(OWLDataExactCardinality desc) {
288                OWLDataPropertyExpression property = desc.getProperty();
289                property = rename(property);
290                OWLDataRange filler = desc.getFiller();
291                filler = rename(filler);
292                int cardinality = desc.getCardinality();
293                if(normalizeCardinalities){
294                        cardinality = 1;
295                }
296                renamedOWLObject = df.getOWLDataExactCardinality(cardinality, property, filler);
297        }
298
299        @Override
300        public void visit(OWLDataMaxCardinality desc) {
301                OWLDataPropertyExpression property = desc.getProperty();
302                property = rename(property);
303                OWLDataRange filler = desc.getFiller();
304                filler = rename(filler);
305                int cardinality = desc.getCardinality();
306                if(normalizeCardinalities){
307                        cardinality = 1;
308                }
309                renamedOWLObject = df.getOWLDataMaxCardinality(cardinality, property, filler);
310        }
311
312        @Override
313        public void visit(OWLObjectInverseOf desc) {
314                OWLObjectPropertyExpression inverse = desc.getInverse();
315                inverse = rename(inverse);
316                renamedOWLObject = df.getOWLObjectInverseOf(inverse);
317        }
318
319        Function<OWLEntity, OWLEntity> classRenamingFn = k -> df.getOWLClass(getIRI("A_" + clsCounter.getAndIncrement()));
320
321        public void setClassRenamingFn(Function<OWLEntity, OWLEntity> classRenamingFn) {
322                this.classRenamingFn = classRenamingFn;
323        }
324
325        @Override
326        public void visit(OWLClass desc) {
327                if(desc.isTopEntity()){
328                        renamedOWLObject = desc;
329                } else {
330//                      OWLEntity newEntity = renaming.computeIfAbsent(desc, k -> df.getOWLClass(getIRI(classVarQueue.poll())));
331                        OWLEntity newEntity = renaming.computeIfAbsent(desc, classRenamingFn);
332                        renamedOWLObject = newEntity;
333
334                }
335        }
336        
337        @Override
338        public void visit(OWLObjectProperty op) {
339                if(op.isTopEntity()){
340                        renamedOWLObject = op;
341                } else {
342                        OWLEntity newEntity = renaming.computeIfAbsent(op, k -> df.getOWLObjectProperty(
343                                        getIRI(propertyVarQueue.poll())));
344                        renamedOWLObject = newEntity;
345                }
346        }
347
348        @Override
349        public void visit(OWLDataProperty dp) {
350                if(dp.isTopEntity()){
351                        renamedOWLObject = dp;
352                } else {
353                        OWLEntity newEntity = renaming.computeIfAbsent(dp,
354                                                                                                                   k -> df.getOWLDataProperty(getIRI(propertyVarQueue.poll())));
355                        renamedOWLObject = newEntity;
356                }
357        }
358
359        @Override
360        public void visit(@Nonnull OWLAnnotationProperty property) {
361
362        }
363
364        @Override
365        public void visit(OWLNamedIndividual ind) {
366                OWLEntity newEntity = renaming.computeIfAbsent(ind, k -> df.getOWLNamedIndividual(
367                                getIRI(individualVarQueue.poll())));
368                renamedOWLObject = newEntity;
369        }
370        
371        private IRI getIRI(String var){
372                return IRI.create(NS + var);
373        }
374
375        @Override
376        public void visit(OWLAnonymousIndividual ind) {
377                OWLEntity newEntity = renaming.get(ind);
378                if(newEntity == null){
379                        newEntity = df.getOWLNamedIndividual(getIRI(individualVarQueue.poll()));
380//                      renaming.put(ind, newEntity);
381                }
382                renamedOWLObject = newEntity;
383        }
384
385        @Override
386        public void visit(OWLDatatype dt) {
387                if(dt.isBuiltIn()) {
388                        renamedOWLObject = dt;
389                } else {
390                        renamedOWLObject = PatternConstants.USER_DEFINED_DATATYPE;
391                }
392        }
393
394        @Override
395        public void visit(OWLDataOneOf desc) {
396                Set<OWLLiteral> literals = desc.getValues();
397                Set<OWLLiteral> renamedLiterals = new TreeSet<>();
398                for (OWLLiteral lit : literals) {
399                        renamedLiterals.add(rename(lit));
400                }
401                renamedOWLObject = df.getOWLDataOneOf(renamedLiterals);
402        }
403
404        @Override
405        public void visit(OWLDataComplementOf desc) {
406                OWLDataRange dataRange = desc.getDataRange();
407                dataRange = rename(dataRange);
408                renamedOWLObject = df.getOWLDataComplementOf(dataRange);
409        }
410
411        @Override
412        public void visit(OWLDataIntersectionOf desc) {
413                List<OWLDataRange> operands = new ArrayList<>(desc.getOperands());
414                Collections.sort(operands, comparator);
415                SortedSet<OWLDataRange> renamedOperands = new TreeSet<>(comparator);
416                for(OWLDataRange expr : operands){
417                        renamedOperands.add(rename(expr));
418                }
419                renamedOWLObject = df.getOWLDataIntersectionOf(renamedOperands);
420        }
421
422        @Override
423        public void visit(OWLDataUnionOf desc) {
424                List<OWLDataRange> operands = new ArrayList<>(desc.getOperands());
425                Collections.sort(operands, comparator);
426                SortedSet<OWLDataRange> renamedOperands = new TreeSet<>(comparator);
427                for(OWLDataRange expr : operands){
428                        renamedOperands.add(rename(expr));
429                }
430                renamedOWLObject = df.getOWLDataUnionOf(renamedOperands);
431        }
432
433        @Override
434        public void visit(OWLDatatypeRestriction desc) {
435                OWLDatatype datatype = desc.getDatatype();
436                Set<OWLFacetRestriction> facetRestrictions = desc.getFacetRestrictions();
437                Set<OWLFacetRestriction> newFacets = facetRestrictions.stream()
438                                .map(facetRestriction -> normalize(facetRestriction))
439                                .sorted()
440                                .collect(Collectors.toSet());
441                renamedOWLObject = df.getOWLDatatypeRestriction(datatype, newFacets);;
442        }
443
444        private OWLFacetRestriction normalize(OWLFacetRestriction fr) {
445                OWLFacet facet = fr.getFacet();
446
447                OWLLiteral value = fr.getFacetValue();
448
449                return df.getOWLFacetRestriction(facet, normalize(value, facet));
450        }
451
452        private OWLLiteral normalize(OWLLiteral lit, OWLFacet facet) {
453                OWLDatatype datatype = lit.getDatatype();
454                OWLLiteral newLit = lit;
455                if(datatype.isBuiltIn()) {
456                        switch(facet) {
457                                case MIN_INCLUSIVE:
458                                case MIN_EXCLUSIVE:
459                                        if(datatype.isDouble()) {
460                                                newLit = df.getOWLLiteral(MIN_DOUBLE_VALUE);
461                                        } else if(datatype.isInteger()) {
462                                                newLit = df.getOWLLiteral(MIN_INTEGER_VALUE);
463                                        } else if(datatype.isFloat()) {
464                                                newLit = df.getOWLLiteral(MIN_FLOAT_VALUE);
465                                        }
466                                        break;
467                                case MAX_INCLUSIVE:
468                                case MAX_EXCLUSIVE:
469                                        if(datatype.isDouble()) {
470                                                newLit = df.getOWLLiteral(MAX_DOUBLE_VALUE);
471                                        } else if(datatype.isInteger()) {
472                                                newLit = df.getOWLLiteral(MAX_INTEGER_VALUE);
473                                        } else if(datatype.isFloat()) {
474                                                newLit = df.getOWLLiteral(MAX_FLOAT_VALUE);
475                                        }
476                                        break;
477                                        default:
478                        }
479
480                }
481                return newLit;
482        }
483
484        @Override
485        public void visit(@Nonnull OWLLiteral node) {
486
487        }
488
489        @Override
490        public void visit(@Nonnull OWLFacetRestriction node) {
491
492        }
493}