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;
020
021import com.google.common.collect.Sets;
022import org.dllearner.core.AbstractReasonerComponent;
023import org.dllearner.core.ComponentInitException;
024import org.dllearner.reasoning.SPARQLReasoner;
025import org.dllearner.utilities.datastructures.SortedSetTuple;
026import org.semanticweb.owlapi.model.*;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
030
031import java.util.*;
032import java.util.stream.Collectors;
033
034/**
035 * TODO: JavaDoc
036 * 
037 * @author Jens Lehmann
038 * 
039 */
040public class Helper {
041
042        private static Logger logger = LoggerFactory.getLogger(Helper.class);
043        private static final OWLDataFactory df = new OWLDataFactoryImpl();
044        
045        public static String prettyPrintNanoSeconds(long nanoSeconds) {
046                return prettyPrintNanoSeconds(nanoSeconds, false, false);
047        }
048
049        // formatiert Nano-Sekunden in einen leserlichen String
050        public static String prettyPrintNanoSeconds(long nanoSeconds, boolean printMicros,
051                        boolean printNanos) {
052                // String str = "";
053                // long seconds = 0;
054                // long milliSeconds = 0;
055                // long microseconds = 0;
056
057                long seconds = nanoSeconds / 1000000000;
058                nanoSeconds = nanoSeconds % 1000000000;
059
060                long milliSeconds = nanoSeconds / 1000000;
061                nanoSeconds = nanoSeconds % 1000000;
062
063                // Mikrosekunden werden immer angezeigt, Sekunden nur falls größer 0
064                String str = "";
065                if (seconds > 0)
066                        str = seconds + "s ";
067                str += milliSeconds + "ms";
068
069                if (printMicros) {
070                        long microSeconds = nanoSeconds / 1000;
071                        nanoSeconds = nanoSeconds % 1000;
072                        str += " " + microSeconds + "usec";
073                }
074                if (printNanos) {
075                        str += " " + nanoSeconds + "ns";
076                }
077
078                return str;
079        }
080        
081        public static String prettyPrintMilliSeconds(long milliSeconds) {
082        
083
084                long seconds = milliSeconds / 1000;
085                milliSeconds = milliSeconds % 1000;
086
087                // Mikrosekunden werden immer angezeigt, Sekunden nur falls größer 0
088                String str = "";
089                if (seconds > 0)
090                        str = seconds + "s ";
091                str += milliSeconds + "ms";
092                
093                return str;
094        }
095
096        public static <T> Set<T> intersectionTuple(Set<T> set, SortedSetTuple<T> tuple) {
097                Set<T> ret = Sets.intersection(set, tuple.getPosSet());
098                ret.retainAll(tuple.getNegSet());
099                return ret;
100        }
101        
102        // Umwandlung von Menge von Individuals auf Menge von Strings
103        public static SortedSet<OWLIndividual> getIndividualSet(Collection<String> individuals) {
104                return individuals.stream()
105                                .map(s -> df.getOWLNamedIndividual(IRI.create(s)))
106                                .collect(Collectors.toCollection(TreeSet::new));
107        }
108
109        public static SortedSetTuple<OWLIndividual> getIndividualTuple(SortedSetTuple<String> tuple) {
110                return new SortedSetTuple<>(getIndividualSet(tuple.getPosSet()),
111                                getIndividualSet(tuple.getNegSet()));
112        }
113
114        public static SortedSetTuple<String> getStringTuple(SortedSetTuple<OWLIndividual> tuple) {
115                return new SortedSetTuple<>(getStringSet(tuple.getPosSet()), getStringSet(tuple
116                                .getNegSet()));
117        }
118
119        // Umwandlung von Menge von Individuals auf Menge von Strings
120        public static SortedSet<String> getStringSet(Collection<OWLIndividual> individuals) {
121                return individuals.stream().
122                                map(OWLIndividual::toStringID).
123                                collect(Collectors.toCollection(TreeSet::new));
124        }
125
126        public static Map<String, SortedSet<String>> getStringMap(
127                        Map<OWLIndividual, SortedSet<OWLIndividual>> roleMembers) {
128                Map<String, SortedSet<String>> ret = new TreeMap<>();
129                for (OWLIndividual i : roleMembers.keySet()) {
130                        ret.put(i.toStringID(), getStringSet(roleMembers.get(i)));
131                }
132                return ret;
133        }
134
135        // concepts case 1: no ignore or allowed list
136        @SuppressWarnings("unchecked")
137        public static <T extends OWLEntity> Set<T> computeEntities(AbstractReasonerComponent rs, EntityType<T> entityType) {
138                // if there is no ignore or allowed list, we just ignore the concepts
139                // of uninteresting namespaces
140                if (entityType == EntityType.CLASS) {
141                        return (Set<T>) rs.getClasses();
142                } else if (entityType == EntityType.OBJECT_PROPERTY) {
143                        return (Set<T>) rs.getObjectProperties();
144                } else if (entityType == EntityType.DATA_PROPERTY) {
145                        return (Set<T>) rs.getDatatypeProperties();
146                }
147                return null;
148        }
149        
150        // concepts case 1: no ignore or allowed list
151        public static Set<OWLClass> computeConcepts(AbstractReasonerComponent rs) {
152                // if there is no ignore or allowed list, we just ignore the concepts
153                // of uninteresting namespaces
154                Set<OWLClass> concepts = rs.getClasses();
155//              Helper.removeUninterestingConcepts(concepts);
156                return concepts;
157        }
158
159        @SuppressWarnings("unchecked")
160        public static <T extends OWLEntity> Set<T> computeEntitiesUsingIgnoreList(AbstractReasonerComponent rs, EntityType<T> entityType, Set<T> ignoredEntites) {
161                Set<T> entities;
162                
163                if (entityType == EntityType.CLASS) {
164                        entities = (Set<T>) rs.getClasses();
165                } else if (entityType == EntityType.OBJECT_PROPERTY) {
166                        entities = (Set<T>) rs.getObjectProperties();
167                } else if (entityType == EntityType.DATA_PROPERTY) {
168                        entities = (Set<T>) rs.getDatatypeProperties();
169                } else {
170                        throw new UnsupportedOperationException("Entity type " + entityType + " currently not supported.");
171                }
172                
173                entities = new TreeSet<>(entities);
174                
175                for (T entity : ignoredEntites) {
176                        boolean success = entities.remove(entity);
177                        if (!success) {
178                                logger.warn("Warning: Ignored entity " + entity + " does not exist in knowledge base.");
179                        }
180                }
181                return entities;
182        }
183        
184        // concepts case 2: ignore list
185        public static Set<OWLClass> computeConceptsUsingIgnoreList(AbstractReasonerComponent rs, Set<OWLClass> ignoredConcepts) {
186                Set<OWLClass> concepts = new TreeSet<>(rs.getClasses());
187//              Helper.removeUninterestingConcepts(concepts);
188                for (OWLClass ac : ignoredConcepts) {
189                        boolean success = concepts.remove(ac);
190                        if (!success)
191                                logger.warn("Warning: Ignored concept " + ac + " does not exist in knowledge base.");
192                }
193                return concepts;
194        }
195        
196        /**
197         * Checks whether the roles exist in background knowledge
198         * @param roles The roles to check.
199         * @return The first non-existing role or null if they are all in the
200         * background knowledge.
201         */
202        //
203        public static OWLObjectProperty checkRoles(AbstractReasonerComponent rs, Set<OWLObjectProperty> roles) {
204                Set<OWLObjectProperty> existingRoles = rs.getObjectProperties();
205                for (OWLObjectProperty ar : roles) {
206                        if(!existingRoles.contains(ar))
207                                return ar;
208                }
209                return null;
210        }
211        
212        /**
213         * Checks whether the entities exist in background knowledge
214         * @param entities The entities to check.
215         * @return The first non-existing entity or null if they are all in the
216         * background knowledge.
217         */
218        public static <T extends OWLEntity> T checkEntities(AbstractReasonerComponent rs, Set<T> entities) {
219                Set<T> existingEntities = (Set<T>) computeEntities(rs, entities.iterator().next().getEntityType());
220                for (T entity : entities) {
221                        if(!existingEntities.contains(entity))
222                                return entity;
223                }
224                return null;
225        }
226        
227        /**
228         * Checks whether the roles exist in background knowledge
229         * @param concepts The concepts to check.
230         * @return The first non-existing role or null if they are all in the
231         * background knowledge.
232         */
233        //
234        public static OWLClass checkConcepts(AbstractReasonerComponent rs, Set<OWLClass> concepts) {
235                Set<OWLClass> existingConcepts = rs.getClasses();
236                for (OWLClass ar : concepts) {
237                        if(!existingConcepts.contains(ar))
238                                return ar;
239                }
240                return null;
241        }
242
243        /**
244         * Checks whether all entities in the given class expression do also occur in the knowledge base.
245         *
246         * @param ce The concept to check.
247         * @return {@code true} if all entities of the class expression occur in the knowledge base,
248         * otherwise {@code false}
249         */
250        public static boolean checkConceptEntities(AbstractReasonerComponent rc, OWLClassExpression ce) {
251                return rc.getClasses().containsAll(ce.getClassesInSignature()) &&
252                                rc.getObjectProperties().containsAll(ce.getObjectPropertiesInSignature()) &&
253                                rc.getDatatypeProperties().containsAll(ce.getDataPropertiesInSignature());
254
255        }
256
257        public static void checkIndividuals(AbstractReasonerComponent reasoner, Set<OWLIndividual> individuals) throws ComponentInitException {
258                if (!(reasoner instanceof SPARQLReasoner)) {
259                        SortedSet<OWLIndividual> allIndividuals = reasoner.getIndividuals();
260
261                        if (!allIndividuals.containsAll(individuals)) {
262                                Set<OWLIndividual> missing = Sets.difference(individuals, allIndividuals);
263                                double percentage = (double) missing.size() / individuals.size();
264                                percentage = Math.round(percentage * 1000.0) / 1000.0;
265                                String str = "The examples (" + (percentage * 100) + " % of total) below are not contained in the knowledge base " +
266                                                "(check spelling and prefixes)\n";
267                                str += missing.toString();
268                                if (missing.size() == individuals.size()) {
269                                        throw new ComponentInitException(str);
270                                }
271                                if (percentage < 0.10) {
272                                        logger.warn(str);
273                                } else {
274                                        logger.error(str);
275                                }
276                        }
277                }
278        }
279
280        public static void displayProgressPercentage(int done, int total) {
281                int size = 5;
282                String iconLeftBoundary = "[";
283                String iconDone = "=";
284                String iconRemain = ".";
285                String iconRightBoundary = "]";
286
287                if (done > total) {
288                        throw new IllegalArgumentException();
289                }
290                int donePercents = (100 * done) / total;
291                int doneLength = size * donePercents / 100;
292
293                StringBuilder bar = new StringBuilder(iconLeftBoundary);
294                for (int i = 0; i < size; i++) {
295                        if (i < doneLength) {
296                                bar.append(iconDone);
297                        } else {
298                                bar.append(iconRemain);
299                        }
300                }
301                bar.append(iconRightBoundary);
302
303                System.out.print("\r" + bar + " " + donePercents + "%");
304
305                if (done == total) {
306                        System.out.print("\n");
307                }
308        }
309
310}