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.algorithms.refinement;
021
022 import java.io.File;
023 import java.text.DecimalFormat;
024 import java.util.Collection;
025 import java.util.Comparator;
026 import java.util.HashMap;
027 import java.util.Iterator;
028 import java.util.LinkedList;
029 import java.util.List;
030 import java.util.Set;
031 import java.util.SortedSet;
032 import java.util.TreeSet;
033
034 import org.apache.log4j.Level;
035 import org.apache.log4j.Logger;
036 import org.dllearner.core.AbstractCELA;
037 import org.dllearner.core.AbstractLearningProblem;
038 import org.dllearner.core.AbstractReasonerComponent;
039 import org.dllearner.core.configurators.ROLearnerConfigurator;
040 import org.dllearner.core.options.BooleanConfigOption;
041 import org.dllearner.core.options.CommonConfigMappings;
042 import org.dllearner.core.options.CommonConfigOptions;
043 import org.dllearner.core.options.ConfigEntry;
044 import org.dllearner.core.options.ConfigOption;
045 import org.dllearner.core.options.DoubleConfigOption;
046 import org.dllearner.core.options.InvalidConfigOptionValueException;
047 import org.dllearner.core.options.StringConfigOption;
048 import org.dllearner.core.owl.Description;
049 import org.dllearner.core.owl.Intersection;
050 import org.dllearner.core.owl.NamedClass;
051 import org.dllearner.core.owl.ObjectProperty;
052 import org.dllearner.core.owl.Thing;
053 import org.dllearner.core.owl.Union;
054 import org.dllearner.learningproblems.EvaluatedDescriptionPosNeg;
055 import org.dllearner.learningproblems.PosNegLP;
056 import org.dllearner.learningproblems.ScorePosNeg;
057 import org.dllearner.refinementoperators.RhoDown;
058 import org.dllearner.utilities.Files;
059 import org.dllearner.utilities.Helper;
060 import org.dllearner.utilities.owl.ConceptComparator;
061 import org.dllearner.utilities.owl.ConceptTransformation;
062 import org.dllearner.utilities.owl.EvaluatedDescriptionPosNegComparator;
063
064 public class ROLearner extends AbstractCELA {
065
066 private ROLearnerConfigurator configurator;
067 @Override
068 public ROLearnerConfigurator getConfigurator(){
069 return configurator;
070 }
071
072 private static Logger logger = Logger
073 .getLogger(AbstractCELA.class);
074
075 private String logLevel = CommonConfigOptions.logLevelDefault;
076
077 public enum Heuristic { LEXICOGRAPHIC, FLEXIBLE }
078
079 // configuration options
080 private boolean writeSearchTree;
081 private File searchTreeFile;
082 private boolean replaceSearchTree = false;
083 private static String defaultSearchTreeFile = "log/searchTree.txt";
084 private Heuristic heuristic = Heuristic.LEXICOGRAPHIC;
085 Set<NamedClass> allowedConcepts;
086 Set<ObjectProperty> allowedRoles;
087 Set<NamedClass> ignoredConcepts;
088 Set<ObjectProperty> ignoredRoles;
089 // these are computed as the result of the previous four settings
090 Set<NamedClass> usedConcepts;
091 Set<ObjectProperty> usedRoles;
092 private boolean applyAllFilter = true;
093 private boolean applyExistsFilter = true;
094 private boolean useTooWeakList = true;
095 private boolean useOverlyGeneralList = true;
096 private boolean useShortConceptConstruction = true;
097 private double horizontalExpansionFactor = 0.6;
098 private boolean improveSubsumptionHierarchy = true;
099 private boolean useAllConstructor = CommonConfigOptions.useAllConstructorDefault;
100 private boolean useExistsConstructor = CommonConfigOptions.useExistsConstructorDefault;
101 //this was added so you can switch algorithm without removing everything not applicable
102 @SuppressWarnings("unused")
103 private boolean useCardinalityRestrictions = CommonConfigOptions.useCardinalityRestrictionsDefault;
104 private boolean useNegation = CommonConfigOptions.useNegationDefault;
105 //TODO different standard options to CommonConfigOptions
106 private boolean useBooleanDatatypes = false;
107
108
109
110 //extended Options
111 private int maxExecutionTimeInSeconds = CommonConfigOptions.maxExecutionTimeInSecondsDefault;
112 private boolean maxExecutionTimeShown = false;
113 private int minExecutionTimeInSeconds = CommonConfigOptions.minExecutionTimeInSecondsDefault;
114 private boolean minExecutionTimeShown = false;
115 private int guaranteeXgoodDescriptions = CommonConfigOptions.guaranteeXgoodDescriptionsDefault;
116 private boolean guaranteeXgoodShown = false;
117
118
119 private boolean quiet = false;
120
121 private boolean stop = false;
122 private boolean isRunning = false;
123
124 private Comparator<Node> nodeComparator;
125 private NodeComparatorStable nodeComparatorStable = new NodeComparatorStable();
126 private ConceptComparator conceptComparator = new ConceptComparator();
127 // comparator for evaluated descriptions
128 private EvaluatedDescriptionPosNegComparator edComparator = new EvaluatedDescriptionPosNegComparator();
129 DecimalFormat df = new DecimalFormat();
130
131 private PosNegLP learningProblem;
132
133 // Menge von Kandidaten für Refinement
134 // (wird für Direktzugriff auf Baumknoten verwendet)
135 private TreeSet<Node> candidates;
136 // während eines Durchlaufs neu gefundene Knoten
137 private List<Node> newCandidates = new LinkedList<Node>();
138 // stabiles candidate set, da sich die Knoten nach dem einfügen nicht
139 // verschieben können => das Set enthält nicht die aktuellen horizontal
140 // expansions, es dient nur dazu die besten Konzepte zu speichern; hat also
141 // keine Funktion im Algorithmus
142 private TreeSet<Node> candidatesStable = new TreeSet<Node>(nodeComparatorStable);
143 // vorhandene Konzepte, die irgendwann als proper eingestuft worden
144 private SortedSet<Description> properRefinements = new TreeSet<Description>(conceptComparator);
145 // speichert Konzept und deren Evaluierung, um sie leicht wiederzufinden für
146 // Strategien wie Konzeptverkürzung etc.
147 // Zahl = covered negatives, -1 = too weak
148 // private Map<Concept, Integer> evaluationCache = new TreeMap<Concept, Integer>(conceptComparator);
149 // Blacklists
150 private SortedSet<Description> tooWeakList = new TreeSet<Description>(conceptComparator);
151 private SortedSet<Description> overlyGeneralList = new TreeSet<Description>(conceptComparator);
152
153 // Lösungen protokollieren
154 boolean solutionFound = false;
155 List<Description> solutions = new LinkedList<Description>();
156
157 // verwendeter Refinement-Operator (momentan werden für Statistik RhoDown-spezifische
158 // Sachen abgefragt)
159 // RefinementOperator operator;
160 RhoDown operator;
161
162 // Variablen zur Einstellung der Protokollierung
163 // boolean quiet = false;
164 boolean showBenchmarkInformation = false;
165 // the previous best node (used only for logging, such that we can
166 // detect whether a new best node has been found since the last time
167 // statistics were printed)
168 private Node previousBestNode;
169
170 // record start node such that other applications can
171 // get information about the search tree
172 private Node startNode;
173
174 // boolean createTreeString = false;
175 // String searchTree = new String();
176 TreeSet<Node> expandedNodes = new TreeSet<Node>(nodeComparatorStable);
177
178 // Konfiguration des Algorithmus
179 // Faktor für horizontale Erweiterung (notwendig für completeness)
180 // double horizontalExpansionFactor = 0.6;
181
182 // statistische Variablen
183 private int maxRecDepth = 0;
184 private int maxNrOfRefinements = 0;
185 private int maxNrOfChildren = 0;
186 private int redundantConcepts = 0;
187 int maximumHorizontalExpansion;
188 int minimumHorizontalExpansion;
189 // private int propernessTests = 0;
190 private int propernessTestsReasoner = 0;
191 private int propernessTestsAvoidedByShortConceptConstruction = 0;
192 private int propernessTestsAvoidedByTooWeakList = 0;
193 private int conceptTestsTooWeakList = 0;
194 private int conceptTestsOverlyGeneralList = 0;
195 private int conceptTestsReasoner = 0;
196
197 // Zeitvariablen
198 private long runtime;
199 private long algorithmStartTime;
200 private long propernessCalcTimeNs = 0;
201 private long propernessCalcReasoningTimeNs = 0;
202 private long childConceptsDeletionTimeNs = 0;
203 private long refinementCalcTimeNs = 0;
204 private long redundancyCheckTimeNs = 0;
205 private long evaluateSetCreationTimeNs = 0;
206 private long improperConceptsRemovalTimeNs = 0;
207 long someTimeNs = 0;
208 int someCount = 0;
209
210 // prefixes
211 private String baseURI;
212
213 public ROLearner(PosNegLP learningProblem, AbstractReasonerComponent reasoningService) {
214 super(learningProblem, reasoningService);
215 this.learningProblem = learningProblem;
216 this.configurator = new ROLearnerConfigurator(this);
217 baseURI = reasoningService.getBaseURI();
218
219 }
220
221 public static Collection<Class<? extends AbstractLearningProblem>> supportedLearningProblems() {
222 Collection<Class<? extends AbstractLearningProblem>> problems = new LinkedList<Class<? extends AbstractLearningProblem>>();
223 problems.add(PosNegLP.class);
224 return problems;
225 }
226
227 public static Collection<ConfigOption<?>> createConfigOptions() {
228 Collection<ConfigOption<?>> options = new LinkedList<ConfigOption<?>>();
229 options.add(new BooleanConfigOption("writeSearchTree", "specifies whether to write a search tree", false));
230 options.add(new StringConfigOption("searchTreeFile","file to use for the search tree", defaultSearchTreeFile));
231 options.add(new BooleanConfigOption("replaceSearchTree","specifies whether to replace the search tree in the log file after each run or append the new search tree", false));
232 StringConfigOption heuristicOption = new StringConfigOption("heuristic", "specifiy the heuristic to use", "lexicographic");
233 heuristicOption.setAllowedValues(new String[] {"lexicographic", "flexible"});
234 options.add(heuristicOption);
235 options.add(new BooleanConfigOption("applyAllFilter", "usage of equivalence ALL R.C AND ALL R.D = ALL R.(C AND D)", true));
236 options.add(new BooleanConfigOption("applyExistsFilter", "usage of equivalence EXISTS R.C OR EXISTS R.D = EXISTS R.(C OR D)", true));
237 options.add(new BooleanConfigOption("useTooWeakList", "try to filter out too weak concepts without sending them to the reasoner", true));
238 options.add(new BooleanConfigOption("useOverlyGeneralList", "try to find overly general concept without sending them to the reasoner", true));
239 options.add(new BooleanConfigOption("useShortConceptConstruction", "shorten concept to see whether they already exist", true));
240 DoubleConfigOption horizExp = new DoubleConfigOption("horizontalExpansionFactor", "horizontal expansion factor (see publication for description)", 0.6);
241 horizExp.setLowerLimit(0.0);
242 horizExp.setUpperLimit(1.0);
243 options.add(horizExp);
244 options.add(new BooleanConfigOption("improveSubsumptionHierarchy", "simplify subsumption hierarchy to reduce search space (see publication for description)", true));
245 // TODO: replace by a general verbosity option for all components
246 options.add(new BooleanConfigOption("quiet", "may be deprecated soon", false));
247 // allowed/ignored concepts/roles could also be a reasoner option (?)
248 options.add(CommonConfigOptions.allowedConcepts());
249 options.add(CommonConfigOptions.ignoredConcepts());
250 options.add(CommonConfigOptions.allowedRoles());
251 options.add(CommonConfigOptions.ignoredRoles());
252 options.add(CommonConfigOptions.useAllConstructor());
253 options.add(CommonConfigOptions.useExistsConstructor());
254 options.add(CommonConfigOptions.useNegation());
255 options.add(CommonConfigOptions.useCardinalityRestrictions());
256 options.add(CommonConfigOptions.useBooleanDatatypes());
257 options.add(CommonConfigOptions.maxExecutionTimeInSeconds());
258 options.add(CommonConfigOptions.minExecutionTimeInSeconds());
259 options.add(CommonConfigOptions.guaranteeXgoodDescriptions());
260 options.add(CommonConfigOptions.getLogLevel());
261 options.add(CommonConfigOptions.getInstanceBasedDisjoints());
262 return options;
263 }
264
265 /* (non-Javadoc)
266 * @see org.dllearner.core.Component#applyConfigEntry(org.dllearner.core.ConfigEntry)
267 */
268 @Override
269 @SuppressWarnings({"unchecked"})
270 public <T> void applyConfigEntry(ConfigEntry<T> entry) throws InvalidConfigOptionValueException {
271 String name = entry.getOptionName();
272 if(name.equals("writeSearchTree"))
273 writeSearchTree = (Boolean) entry.getValue();
274 else if(name.equals("searchTreeFile"))
275 searchTreeFile = new File((String)entry.getValue());
276 else if(name.equals("replaceSearchTree"))
277 replaceSearchTree = (Boolean) entry.getValue();
278 else if(name.equals("heuristic")) {
279 String value = (String) entry.getValue();
280 if(value.equals("lexicographic"))
281 heuristic = Heuristic.LEXICOGRAPHIC;
282 else
283 heuristic = Heuristic.FLEXIBLE;
284 } else if(name.equals("allowedConcepts")) {
285 allowedConcepts = CommonConfigMappings.getAtomicConceptSet((Set<String>)entry.getValue());
286 } else if(name.equals("allowedRoles")) {
287 allowedRoles = CommonConfigMappings.getAtomicRoleSet((Set<String>)entry.getValue());
288 } else if(name.equals("ignoredConcepts")) {
289 ignoredConcepts = CommonConfigMappings.getAtomicConceptSet((Set<String>)entry.getValue());
290 } else if(name.equals("ignoredRoles")) {
291 ignoredRoles = CommonConfigMappings.getAtomicRoleSet((Set<String>)entry.getValue());
292 } else if(name.equals("applyAllFilter")) {
293 applyAllFilter = (Boolean) entry.getValue();
294 } else if(name.equals("applyExistsFilter")) {
295 applyExistsFilter = (Boolean) entry.getValue();
296 } else if(name.equals("useTooWeakList")) {
297 useTooWeakList = (Boolean) entry.getValue();
298 } else if(name.equals("useOverlyGeneralList")) {
299 useOverlyGeneralList = (Boolean) entry.getValue();
300 } else if(name.equals("useShortConceptConstruction")) {
301 useShortConceptConstruction = (Boolean) entry.getValue();
302 } else if(name.equals("horzontalExpansionFactor")) {
303 horizontalExpansionFactor = (Double) entry.getValue();
304 } else if(name.equals("improveSubsumptionHierarchy")) {
305 improveSubsumptionHierarchy = (Boolean) entry.getValue();
306 } else if(name.equals("useAllConstructor")) {
307 useAllConstructor = (Boolean) entry.getValue();
308 } else if(name.equals("useExistsConstructor")) {
309 useExistsConstructor = (Boolean) entry.getValue();
310 }else if(name.equals("useCardinalityRestrictions")) {
311 useCardinalityRestrictions = (Boolean) entry.getValue();
312 } else if(name.equals("useNegation")) {
313 useNegation = (Boolean) entry.getValue();
314 } else if(name.equals("useBooleanDatatypes")) {
315 useBooleanDatatypes = (Boolean) entry.getValue();
316 }else if(name.equals("maxExecutionTimeInSeconds")) {
317 maxExecutionTimeInSeconds = (Integer) entry.getValue();
318 }else if(name.equals("minExecutionTimeInSeconds")) {
319 minExecutionTimeInSeconds = (Integer) entry.getValue();
320 }else if(name.equals("guaranteeXgoodDescriptions")) {
321 guaranteeXgoodDescriptions = (Integer) entry.getValue();
322 } else if(name.equals("logLevel")) {
323 logLevel = ((String)entry.getValue()).toUpperCase();
324 }
325
326 }
327
328 /* (non-Javadoc)
329 * @see org.dllearner.core.Component#init()
330 */
331 @Override
332 public void init() {
333 // set log level if the option has been set
334 if(!logLevel.equals(CommonConfigOptions.logLevelDefault))
335 logger.setLevel(Level.toLevel(logLevel,Level.toLevel(CommonConfigOptions.logLevelDefault)));
336
337 if(searchTreeFile == null)
338 searchTreeFile = new File(defaultSearchTreeFile);
339
340 if(writeSearchTree)
341 Files.clearFile(searchTreeFile);
342
343 // adjust heuristic
344 if(heuristic == Heuristic.LEXICOGRAPHIC) {
345 nodeComparator = new NodeComparator();
346 } else {
347 nodeComparator = new NodeComparator2(learningProblem.getNegativeExamples().size(), learningProblem.getPercentPerLengthUnit());
348 }
349
350 // this.learningProblem2 = learningProblem2;
351 operator = new RhoDown(reasoner, applyAllFilter, applyExistsFilter, useAllConstructor, useExistsConstructor, useNegation, useBooleanDatatypes);
352
353 // candidate sets entsprechend der gewählten Heuristik initialisieren
354 candidates = new TreeSet<Node>(nodeComparator);
355 // newCandidates = new TreeSet<Node>(nodeComparator);
356
357 if(allowedConcepts != null) {
358 // sanity check to control if no non-existing concepts are in the list
359 Helper.checkConcepts(reasoner, allowedConcepts);
360 usedConcepts = allowedConcepts;
361 } else if(ignoredConcepts != null) {
362 usedConcepts = Helper.computeConceptsUsingIgnoreList(reasoner, ignoredConcepts);
363 } else {
364 usedConcepts = Helper.computeConcepts(reasoner);
365 }
366
367 if(allowedRoles != null) {
368 Helper.checkRoles(reasoner, allowedRoles);
369 usedRoles = allowedRoles;
370 } else if(ignoredRoles != null) {
371 Helper.checkRoles(reasoner, ignoredRoles);
372 usedRoles = Helper.difference(reasoner.getObjectProperties(), ignoredRoles);
373 } else {
374 usedRoles = reasoner.getObjectProperties();
375 }
376
377 // prepare subsumption and role hierarchies, because they are needed
378 // during the run of the algorithm
379 // reasoner.prepareSubsumptionHierarchy(usedConcepts);
380 if(improveSubsumptionHierarchy)
381 reasoner.getClassHierarchy().thinOutSubsumptionHierarchy();
382 // reasoner.prepareRoleHierarchy(usedRoles);
383 }
384
385 public static String getName() {
386 return "refinement operator based learning algorithm";
387 }
388
389 private int coveredNegativesOrTooWeak(Description concept) {
390 return learningProblem.coveredNegativeExamplesOrTooWeak(concept);
391 }
392
393 private int getNumberOfNegatives() {
394 return learningProblem.getNegativeExamples().size();
395 }
396
397 // Kernalgorithmus
398 @Override
399 public void start() {
400 isRunning = true;
401 runtime=System.currentTimeMillis();
402 // Suche wird mit Top-Konzept gestartet
403 Thing top = new Thing();
404 Node topNode = new Node(top);
405 // int coveredNegativeExamples = learningProblem.coveredNegativeExamplesOrTooWeak(top);
406 // aus Top folgen immer alle negativen Beispiele, d.h. es ist nur eine Lösung, wenn
407 // es keine negativen Beispiele gibt
408 int coveredNegativeExamples = getNumberOfNegatives();
409 topNode.setCoveredNegativeExamples(coveredNegativeExamples);
410 // topNode.setHorizontalExpansion(1); // die 0 ist eigentlich richtig, da keine Refinements
411 // der Länge 1 untersucht wurden
412 candidates.add(topNode);
413 candidatesStable.add(topNode);
414 startNode = topNode;
415 // Abbruchvariable => beachten, dass bereits TOP eine Lösung sein kann
416 solutionFound = (coveredNegativeExamples == 0);
417 solutions = new LinkedList<Description>();
418 if(solutionFound)
419 solutions.add(top);
420
421 int loop = 0;
422
423 // Voreinstellung für horizontal expansion
424 maximumHorizontalExpansion = 0;
425 minimumHorizontalExpansion = 0;
426
427 algorithmStartTime = System.nanoTime();
428
429 //second set of lines below, sometimes doesn't go into while, see above
430 handleStoppingConditions();
431
432 // TODO: effizienter Traversal der Subsumption-Hierarchie
433 // TODO: Ãquivalenzen nutzen
434 // TODO: Gibt es auch eine andere Abbruchbedingung? Es könnte sein, dass irgendwann keine
435 // proper refinements mehr gefunden werden, aber wie stelle man das fest?
436 while(!solutionFound && !stop) {
437
438 if(!quiet)
439 printStatistics(false);
440
441 // besten Knoten nach Heuristik auswählen
442 Node bestNode = candidates.last();
443 // besten Knoten erweitern
444 // newCandidates = new TreeSet<Node>(nodeComparator);
445 newCandidates.clear();
446 candidates.remove(bestNode);
447 extendNodeProper(bestNode, bestNode.getHorizontalExpansion()+1);
448 candidates.add(bestNode);
449 candidates.addAll(newCandidates);
450 candidatesStable.addAll(newCandidates);
451
452 // minimum horizontal expansion berechnen
453 if(bestNode.getHorizontalExpansion()>maximumHorizontalExpansion)
454 maximumHorizontalExpansion = bestNode.getHorizontalExpansion();
455 minimumHorizontalExpansion = (int) Math.floor(horizontalExpansionFactor*maximumHorizontalExpansion);
456
457 // neu: es werden solange Knoten erweitert bis wirklich jeder Knoten die
458 // notwendige minimum horizontal expansion hat
459 boolean nodesExpanded;
460 do {
461 nodesExpanded = false;
462
463
464 // es darf nicht candidatesStable geklont werden, da diese Menge nicht
465 // aktualisiert wird, also die falschen horizontal expansions vorliegen
466 // TODO: bei Tests war die Performance der clone-Operation ganz gut, aber
467 // es skaliert natürlich nicht so gut mit gröÃer werdenden candidate set
468 // => Lösung ist vielleicht einfach einen Iterator zu verwenden und das
469 // aktuelle Konzept gleich hier zu löschen (wird dann bei expansion wieder
470 // hinzugefügt)
471 // TreeSet<Node> candidatesClone = (TreeSet<Node>) candidates.clone();
472 newCandidates.clear();
473
474
475 // for(Node candidate : candidatesClone) {
476 Iterator<Node> it = candidates.iterator();
477 List<Node> changedNodes = new LinkedList<Node>();
478 while(it.hasNext()){
479 Node candidate = it.next();
480 // alle Kandidaten, die nicht too weak sind und unter minimumHorizontalExpansion
481 // liegen, werden erweitert
482 if(!candidate.isTooWeak() && candidate.getHorizontalExpansion()<minimumHorizontalExpansion) {
483 // Vorsicht, falls candidates irgendwann in extendProper benutzt
484 // werden sollten! Es könnten auf diese Weise Knoten fehlen
485 // (momentan wird candidates nur zur Auswahl des besten Knotens
486 // benutzt).
487 it.remove();
488
489 extendNodeProper(candidate, minimumHorizontalExpansion);
490 nodesExpanded = true;
491
492 changedNodes.add(candidate);
493 }
494 }
495
496 long someTimeStart = System.nanoTime();
497 someCount++;
498 // geänderte temporär entfernte Knoten wieder hinzufügen
499 candidates.addAll(changedNodes);
500 // neu gefundene Knoten hinzufügen
501 candidates.addAll(newCandidates);
502 candidatesStable.addAll(newCandidates);
503 someTimeNs += System.nanoTime() - someTimeStart;
504
505 } while(nodesExpanded && !stop);
506
507 //System.out.println("candidate set:");
508 //for(Node n : candidates) {
509 // System.out.println(n);
510 //}
511
512 if(writeSearchTree) {
513 // String treeString = "";
514 String treeString = "best expanded node: " + bestNode+ "\n";
515 if(expandedNodes.size()>1) {
516 treeString += "all expanded nodes:\n"; // due to minimum horizontal expansion:\n";
517 for(Node n : expandedNodes) {
518 treeString += " " + n + "\n";
519 }
520 }
521 expandedNodes.clear();
522 treeString += "horizontal expansion: " + minimumHorizontalExpansion + " to " + maximumHorizontalExpansion + "\n";
523 treeString += topNode.getTreeString();
524 treeString += "\n";
525 // System.out.println(treeString);
526 // searchTree += treeString + "\n";
527 // TODO: ev. immer nur einen search tree speichern und den an die
528 // Datei anhängen => spart Speicher
529 if(replaceSearchTree)
530 Files.createFile(searchTreeFile, treeString);
531 else
532 Files.appendFile(searchTreeFile, treeString);
533 }//write search tree
534
535 // Anzahl Schleifendurchläufe
536 loop++;
537
538 if(!quiet)
539 logger.debug("--- loop " + loop + " finished ---");
540
541 handleStoppingConditions();
542
543 }//end while
544
545
546
547
548 // Suchbaum in Datei schreiben
549 // if(writeSearchTree)
550 // Files.createFile(searchTreeFile, searchTree);
551
552 // Ergebnisausgabe
553 /*
554 System.out.println("candidate set:");
555 for(Node n : candidates) {
556 System.out.println(n);
557 }*/
558
559 // Set<Concept> solutionsSorted = new TreeSet(conceptComparator);
560 // solutionsSorted.addAll(solutions);
561
562 // System.out.println("retrievals:");
563 // for(Concept c : ReasonerComponent.retrievals) {
564 // System.out.println(c);
565 // }
566
567 if(solutionFound) {
568 logger.info("\nsolutions:");
569 int show=1;
570 for(Description c : solutions) {
571 logger.info(show+": " +c.toString(baseURI,null) + " (length " + c.getLength() +", depth " + c.getDepth() + ")");
572 //TODO remove this line maybe
573 // watch for String.replace Quick hack
574 logger.info(" MANCHESTER: " +
575 c.toManchesterSyntaxString(baseURI, new HashMap<String,String>()).
576 replace("\"", ""));
577 logger.info(" KBSyntax: " + c.toKBSyntaxString());
578 if(show>=5){break;}
579 show++;
580 }
581
582 }
583 logger.info(" horizontal expansion: " + minimumHorizontalExpansion + " to " + maximumHorizontalExpansion);
584 logger.info(" size of candidate set: " + candidates.size());
585
586 //logger.trace("test");
587 //logger.trace(solutions.size());
588 printBestSolutions(0);
589 printStatistics(true);
590
591 if(stop)
592 logger.info("Algorithm stopped.");
593 else
594 logger.info("Algorithm terminated succesfully.");
595
596 isRunning = false;
597 }
598
599 // einfache Erweiterung des Knotens (ohne properness)
600 @SuppressWarnings({"unused"})
601 private void extendNodeSimple(Node node, int maxLength) {
602
603 }
604
605 private void extendNodeProper(Node node, int maxLength) {
606 // Rekursionsanfang ist das Konzept am Knoten selbst; danach wird der Operator
607 // so lange darauf angewandt bis alle proper refinements bis zu maxLength
608 // gefunden wurden
609 long propCalcNsStart = System.nanoTime();
610
611 if(writeSearchTree)
612 expandedNodes.add(node);
613
614 if(node.getChildren().size()>maxNrOfChildren)
615 maxNrOfChildren = node.getChildren().size();
616
617 // Knoten in instabiler Menge muss aktualisiert werden
618 // => wird jetzt schon vom Algorithmus entfernt
619 /*
620 boolean remove = candidates.remove(node);
621
622 if(!remove) {
623 System.out.println(candidates);
624 System.out.println(candidatesStable);
625 System.out.println(node);
626
627 throw new RuntimeException("remove failed");
628 }*/
629
630 extendNodeProper(node, node.getConcept(), maxLength, 0);
631 node.setHorizontalExpansion(maxLength);
632
633 // wird jetzt schon im Kernalgorithmus hinzugefügt
634 /*
635 boolean add = candidates.add(node);
636 if(!add) {
637 throw new RuntimeException("add failed");
638 }*/
639
640 // Knoten wird entfernt und wieder hinzugefügt, da sich seine
641 // Position geändert haben könnte => geht noch nicht wg. ConcurrentModification
642 // falls Knoten wg. min. horiz. exp. expandiert werden
643 // candidates.remove(node);
644 // candidates.add(node);
645 propernessCalcTimeNs += (System.nanoTime()-propCalcNsStart);
646 }
647
648
649
650 // für alle proper refinements von concept bis maxLength werden Kinderknoten
651 // für node erzeugt;
652 // recDepth dient nur zur Protokollierung
653 private void extendNodeProper(Node node, Description concept, int maxLength, int recDepth) {
654
655 // führe Methode nicht aus, wenn Algorithmus gestoppt wurde (alle rekursiven Funktionsaufrufe
656 // werden nacheinander abgebrochen, so dass ohne weitere Reasoninganfragen relativ schnell beendet wird)
657 if(stop)
658 return;
659
660 if(recDepth > maxRecDepth)
661 maxRecDepth = recDepth;
662
663 // Refinements berechnen => hier dürfen dürfen refinements <= horizontal expansion
664 // des Konzepts nicht gelöscht werden!
665 long refinementCalcTimeNsStart = System.nanoTime();
666 Set<Description> refinements = operator.refine(concept, maxLength, null);
667 refinementCalcTimeNs += System.nanoTime() - refinementCalcTimeNsStart;
668
669 if(refinements.size()>maxNrOfRefinements)
670 maxNrOfRefinements = refinements.size();
671
672 long childConceptsDeletionTimeNsStart = System.nanoTime();
673 // entferne aus den refinements alle Konzepte, die bereits Kinder des Knotens sind
674 // for(Node n : node.getChildren()) {
675 // refinements.remove(n.getConcept());
676 // }
677
678 // das ist viel schneller, allerdings bekommt man ein anderes candidate set(??)
679 refinements.removeAll(node.getChildConcepts());
680
681 childConceptsDeletionTimeNs += System.nanoTime() - childConceptsDeletionTimeNsStart;
682
683 long evaluateSetCreationTimeNsStart = System.nanoTime();
684
685 // alle Konzepte, die länger als horizontal expansion sind, müssen ausgewertet
686 // werden
687 Set<Description> toEvaluateConcepts = new TreeSet<Description>(conceptComparator);
688 Iterator<Description> it = refinements.iterator();
689 // for(Concept refinement : refinements) {
690 while(it.hasNext()) {
691 Description refinement = it.next();
692 if(refinement.getLength()>node.getHorizontalExpansion()) {
693 // TODO: an dieser Stelle könnte man Algorithmen ansetzen lassen, die
694 // versuchen properness-Anfragen zu vermeiden:
695 // 1. Konzept kürzen und schauen, ob es Mutterkonzept entspricht
696 // 2. Blacklist, die überprüft, ob Konzept too weak ist
697 // (dann ist es auch proper)
698
699 // sagt aus, ob festgestellt wurde, ob refinement proper ist
700 // (sagt nicht aus, dass das refinement proper ist!)
701 boolean propernessDetected = false;
702
703 // 1. short concept construction
704 if(useShortConceptConstruction) {
705 // kurzes Konzept konstruieren
706 Description shortConcept = ConceptTransformation.getShortConcept(refinement, conceptComparator);
707 int n = conceptComparator.compare(shortConcept, concept);
708
709 // Konzepte sind gleich also Refinement improper
710 if(n==0) {
711 propernessTestsAvoidedByShortConceptConstruction++;
712 propernessDetected = true;
713 }
714 }
715
716 // 2. too weak test
717 if(!propernessDetected && useTooWeakList) {
718 if(refinement instanceof Intersection) {
719 boolean tooWeakElement = containsTooWeakElement((Intersection)refinement);
720 if(tooWeakElement) {
721 propernessTestsAvoidedByTooWeakList++;
722 conceptTestsTooWeakList++;
723 propernessDetected = true;
724 tooWeakList.add(refinement);
725
726 // Knoten wird direkt erzeugt (es ist buganfällig zwei Plätze
727 // zu haben, an denen Knoten erzeugt werden, aber es erscheint
728 // hier am sinnvollsten)
729 properRefinements.add(refinement);
730 tooWeakList.add(refinement);
731
732 Node newNode = new Node(refinement);
733 newNode.setHorizontalExpansion(refinement.getLength()-1);
734 newNode.setTooWeak(true);
735 newNode.setQualityEvaluationMethod(Node.QualityEvaluationMethod.TOO_WEAK_LIST);
736 node.addChild(newNode);
737
738 // Refinement muss gelöscht werden, da es proper ist
739 it.remove();
740 }
741 }
742 }
743
744 // properness konnte nicht vorher ermittelt werden
745 if(!propernessDetected)
746 toEvaluateConcepts.add(refinement);
747
748
749 }
750 }
751 evaluateSetCreationTimeNs += System.nanoTime() - evaluateSetCreationTimeNsStart;
752
753 // System.out.println(toEvaluateConcepts.size());
754
755 Set<Description> improperConcepts = null;
756 if(toEvaluateConcepts.size()>0) {
757 // Test aller Konzepte auf properness (mit DIG in nur einer Anfrage)
758 long propCalcReasoningStart = System.nanoTime();
759 improperConcepts = reasoner.isSuperClassOf(toEvaluateConcepts, concept);
760 propernessTestsReasoner+=toEvaluateConcepts.size();
761 // boolean isProper = !learningProblem.getReasonerComponent().subsumes(refinement, concept);
762 propernessCalcReasoningTimeNs += System.nanoTime() - propCalcReasoningStart;
763 }
764
765 long improperConceptsRemovalTimeNsStart = System.nanoTime();
766 // die improper Konzepte werden von den auszuwertenden gelöscht, d.h.
767 // alle proper concepts bleiben übrig (einfache Umbenennung)
768 if(improperConcepts != null)
769 toEvaluateConcepts.removeAll(improperConcepts);
770 Set<Description> properConcepts = toEvaluateConcepts;
771 // alle proper concepts von refinements löschen
772 refinements.removeAll(properConcepts);
773 improperConceptsRemovalTimeNs += System.nanoTime() - improperConceptsRemovalTimeNsStart;
774
775 for(Description refinement : properConcepts) {
776 long redundancyCheckTimeNsStart = System.nanoTime();
777 boolean nonRedundant = properRefinements.add(refinement);
778 redundancyCheckTimeNs += System.nanoTime() - redundancyCheckTimeNsStart;
779
780 if(!nonRedundant)
781 redundantConcepts++;
782
783 // es wird nur ein neuer Knoten erzeugt, falls das Konzept nicht
784 // schon existiert
785 if(nonRedundant) {
786
787 // Knoten erzeugen
788 Node newNode = new Node(refinement);
789 // die -1 ist wichtig, da sonst keine gleich langen Refinements
790 // für den neuen Knoten erlaubt wären z.B. person => male
791 newNode.setHorizontalExpansion(refinement.getLength()-1);
792
793
794 // hier finden Tests statt, die Retrieval-Anfrage vermeiden sollen
795 /*
796 Integer n = evaluationCache.get(concept);
797 // Konzept gefunden
798 if(n!=null) {
799 // Knoten erzeugen
800 Node newNode = new Node(refinement);
801 newNode.setHorizontalExpansion(refinement.getLength()-1);
802 node.addChild(newNode);
803
804 // too weak
805 if(n==-1) {
806 newNode.setTooWeak(true);
807 // nicht too weak
808 } else {
809 // feststellen, ob proper => geht so nicht
810 // gleiche covered negatives bedeutet nicht improper
811 boolean proper = (n==node.getCoveredNegativeExamples());
812 newNode.setCoveredNegativeExamples(n);
813
814 }
815 // Konzept nicht gefunden => muss ausgewertet werden
816 } else {
817 toEvaluateConcepts.add(refinement);
818 }
819 */
820
821 boolean qualityKnown = false;
822 int quality = -2;
823
824 // overly general list verwenden
825 if(useOverlyGeneralList && refinement instanceof Union) {
826 if(containsOverlyGeneralElement((Union)refinement)) {
827 conceptTestsOverlyGeneralList++;
828 quality = getNumberOfNegatives();
829 qualityKnown = true;
830 newNode.setQualityEvaluationMethod(Node.QualityEvaluationMethod.OVERLY_GENERAL_LIST);
831 }
832 }
833
834 // Qualität des Knotens auswerten
835 if(!qualityKnown) {
836 long propCalcReasoningStart2 = System.nanoTime();
837 conceptTestsReasoner++;
838 quality = coveredNegativesOrTooWeak(refinement);
839 propernessCalcReasoningTimeNs += System.nanoTime() - propCalcReasoningStart2;
840 newNode.setQualityEvaluationMethod(Node.QualityEvaluationMethod.REASONER);
841 }
842
843 if(quality == -1) {
844 newNode.setTooWeak(true);
845 // Blacklist für too weak concepts
846 tooWeakList.add(refinement);
847 } else {
848 // Lösung gefunden
849 if(quality == 0) {
850 solutionFound = true;
851 solutions.add(refinement);
852 }
853
854 newNode.setCoveredNegativeExamples(quality);
855 newCandidates.add(newNode);
856 // candidates.add(newNode);
857 // candidatesStable.add(newNode);
858
859
860 if(quality == getNumberOfNegatives())
861 overlyGeneralList.add(refinement);
862
863 // System.out.print(".");
864 }
865
866 node.addChild(newNode);
867 }
868 }
869
870
871 /*
872 Iterator<Concept> it = refinements.iterator();
873 while(it.hasNext()) {
874 Concept refinement = it.next();
875 if(refinement.getLength()>node.getHorizontalExpansion()) {
876 // Test auf properness
877 long propCalcReasoningStart = System.nanoTime();
878 boolean isProper = !learningProblem.getReasonerComponent().subsumes(refinement, concept);
879 propernessCalcReasoningTimeNs += System.nanoTime() - propCalcReasoningStart;
880
881 if(isProper) {
882 long redundancyCheckTimeNsStart = System.nanoTime();
883 boolean nonRedundant = properRefinements.add(refinement);
884 redundancyCheckTimeNs += System.nanoTime() - redundancyCheckTimeNsStart;
885
886 if(!nonRedundant)
887 redundantConcepts++;
888
889 // es wird nur ein neuer Knoten erzeugt, falls das Konzept nicht
890 // schon existiert
891 if(nonRedundant) {
892
893 // Knoten erzeugen
894 Node newNode = new Node(refinement);
895 // die -1 ist wichtig, da sonst keine gleich langen Refinements
896 // für den neuen Knoten erlaubt wären z.B. person => male
897 newNode.setHorizontalExpansion(refinement.getLength()-1);
898 node.addChild(newNode);
899
900 // Qualität des Knotens auswerten
901 long propCalcReasoningStart2 = System.nanoTime();
902 int quality = learningProblem.coveredNegativeExamplesOrTooWeak(refinement);
903 propernessCalcReasoningTimeNs += System.nanoTime() - propCalcReasoningStart2;
904
905 if(quality == -1) {
906 newNode.setTooWeak(true);
907 } else {
908 // Lösung gefunden
909 if(quality == 0) {
910 solutionFound = true;
911 solutions.add(refinement);
912 }
913
914 newNode.setCoveredNegativeExamples(quality);
915 newCandidates.add(newNode);
916
917 // System.out.print(".");
918 }
919 }
920
921 // jedes proper Refinement wird gelöscht
922 it.remove();
923
924 }
925 }
926 }
927 */
928
929
930
931 // es sind jetzt noch alle Konzepte übrig, die improper refinements sind
932 // auf jedem dieser Konzepte wird die Funktion erneut aufgerufen, da sich
933 // proper refinements ergeben könnten
934 for(Description refinement : refinements) {
935 // for(int i=0; i<=recDepth; i++)
936 // System.out.print(" ");
937 // System.out.println("call: " + refinement + " [maxLength " + maxLength + "]");
938 extendNodeProper(node, refinement, maxLength, recDepth+1);
939 // for(int i=0; i<=recDepth; i++)
940 // System.out.print(" ");
941 // System.out.println("finished: " + refinement + " [maxLength " + maxLength + "]");
942 }
943 }
944
945 private void printStatistics(boolean finalStats) {
946 // TODO: viele Tests haben ergeben, dass man nie 100% mit der Zeitmessung abdecken
947 // kann (zum einen weil Stringausgabe verzögert erfolgt und zum anderen weil
948 // Funktionsaufrufe, garbage collection, Zeitmessung selbst auch Zeit benötigt);
949 // es empfiehlt sich folgendes Vorgehen:
950 // - Messung der Zeit eines Loops im Algorithmus
951 // - Messung der Zeit für alle node extensions innerhalb eines Loops
952 // => als Normalisierungsbasis empfehlen sich dann die Loopzeit statt
953 // Algorithmuslaufzeit
954 // ... momentan kann es aber auch erstmal so lassen
955
956 long algorithmRuntime = System.nanoTime() - algorithmStartTime;
957
958 if(!finalStats) {
959 Node bestNode = candidatesStable.last();
960 boolean newBestNodeFound = false;
961 if(!bestNode.equals(previousBestNode)) {
962 newBestNodeFound = true;
963 previousBestNode = bestNode;
964 }
965 if(newBestNodeFound)
966 logger.info("currently best node: " + bestNode);
967
968 // Refinementoperator auf Konzept anwenden
969 String bestNodeString = "currently best node: " + candidatesStable.last();
970 // searchTree += bestNodeString + "\n";
971 if(!newBestNodeFound)
972 logger.debug(bestNodeString);
973 String expandedNodeString = "next expanded node: " + candidates.last();
974 // searchTree += expandedNodeString + "\n";
975 logger.debug(expandedNodeString);
976 logger.debug("algorithm runtime " + Helper.prettyPrintNanoSeconds(algorithmRuntime));
977 String expansionString = "horizontal expansion: " + minimumHorizontalExpansion + " to " + maximumHorizontalExpansion;
978 // searchTree += expansionString + "\n";
979 logger.debug(expansionString);
980 logger.debug("size of candidate set: " + candidates.size());
981 // System.out.println("properness max recursion depth: " + maxRecDepth);
982 // System.out.println("max. number of one-step refinements: " + maxNrOfRefinements);
983 // System.out.println("max. number of children of a node: " + maxNrOfChildren);
984 logger.debug("subsumption time: " + Helper.prettyPrintNanoSeconds(reasoner.getSubsumptionReasoningTimeNs()));
985 logger.debug("instance check time: " + Helper.prettyPrintNanoSeconds(reasoner.getInstanceCheckReasoningTimeNs()));
986 }
987
988 if(showBenchmarkInformation) {
989
990
991 long reasoningTime = reasoner.getOverallReasoningTimeNs();
992 double reasoningPercentage = 100 * reasoningTime/(double)algorithmRuntime;
993 long propWithoutReasoning = propernessCalcTimeNs-propernessCalcReasoningTimeNs;
994 double propPercentage = 100 * propWithoutReasoning/(double)algorithmRuntime;
995 double deletionPercentage = 100 * childConceptsDeletionTimeNs/(double)algorithmRuntime;
996 long subTime = reasoner.getSubsumptionReasoningTimeNs();
997 double subPercentage = 100 * subTime/(double)algorithmRuntime;
998 double refinementPercentage = 100 * refinementCalcTimeNs/(double)algorithmRuntime;
999 double redundancyCheckPercentage = 100 * redundancyCheckTimeNs/(double)algorithmRuntime;
1000 double evaluateSetCreationTimePercentage = 100 * evaluateSetCreationTimeNs/(double)algorithmRuntime;
1001 double improperConceptsRemovalTimePercentage = 100 * improperConceptsRemovalTimeNs/(double)algorithmRuntime;
1002 double mComputationTimePercentage = 100 * operator.mComputationTimeNs/(double)algorithmRuntime;
1003 double topComputationTimePercentage = 100 * operator.topComputationTimeNs/(double)algorithmRuntime;
1004 double cleanTimePercentage = 100 * ConceptTransformation.cleaningTimeNs/(double)algorithmRuntime;
1005 double onnfTimePercentage = 100 * ConceptTransformation.onnfTimeNs/(double)algorithmRuntime;
1006 double shorteningTimePercentage = 100 * ConceptTransformation.shorteningTimeNs/(double)algorithmRuntime;
1007
1008 // nur temporär
1009 double someTimePercentage = 100 * someTimeNs/(double)algorithmRuntime;
1010
1011 System.out.println("reasoning percentage: " + df.format(reasoningPercentage) + "%");
1012 System.out.println(" subsumption check time: " + df.format(subPercentage) + "%");
1013 System.out.println("proper calculation percentage (wo. reasoning): " + df.format(propPercentage) + "%");
1014 System.out.println(" deletion time percentage: " + df.format(deletionPercentage) + "%");
1015 System.out.println(" refinement calculation percentage: " + df.format(refinementPercentage) + "%");
1016 System.out.println(" some time percentage: " + df.format(someTimePercentage) + "% " + Helper.prettyPrintNanoSeconds(someTimeNs) + " " + someCount + " times");
1017 System.out.println(" m calculation percentage: " + df.format(mComputationTimePercentage) + "%");
1018 System.out.println(" top calculation percentage: " + df.format(topComputationTimePercentage) + "%");
1019 System.out.println(" redundancy check percentage: " + df.format(redundancyCheckPercentage) + "%");
1020 System.out.println(" evaluate set creation time percentage: " + df.format(evaluateSetCreationTimePercentage) + "%");
1021 System.out.println(" improper concepts removal time percentage: " + df.format(improperConceptsRemovalTimePercentage) + "%");
1022 System.out.println("clean time percentage: " + df.format(cleanTimePercentage) + "%");
1023 System.out.println("onnf time percentage: " + df.format(onnfTimePercentage) + "%");
1024 System.out.println("shortening time percentage: " + df.format(shorteningTimePercentage) + "%");
1025 }
1026 logger.debug("properness tests (reasoner/short concept/too weak list): " + propernessTestsReasoner + "/" + propernessTestsAvoidedByShortConceptConstruction
1027 + "/" + propernessTestsAvoidedByTooWeakList);
1028 logger.debug("concept tests (reasoner/too weak list/overly general list/redundant concepts): " + conceptTestsReasoner + "/"
1029 + conceptTestsTooWeakList + "/" + conceptTestsOverlyGeneralList + "/" + redundantConcepts);
1030 }
1031
1032 private boolean containsTooWeakElement(Intersection mc) {
1033 for(Description child : mc.getChildren()) {
1034 if(tooWeakList.contains(child))
1035 return true;
1036 }
1037 return false;
1038 }
1039
1040 private boolean containsOverlyGeneralElement(Union md) {
1041 for(Description child : md.getChildren()) {
1042 if(overlyGeneralList.contains(child))
1043 return true;
1044 }
1045 return false;
1046 }
1047
1048 @Override
1049 public Description getCurrentlyBestDescription() {
1050 return candidatesStable.last().getConcept();
1051 }
1052
1053 @Override
1054 public EvaluatedDescriptionPosNeg getCurrentlyBestEvaluatedDescription() {
1055 return new EvaluatedDescriptionPosNeg(candidatesStable.last().getConcept(), getSolutionScore());
1056 }
1057
1058 @Override
1059 public TreeSet<EvaluatedDescriptionPosNeg> getCurrentlyBestEvaluatedDescriptions() {
1060 int count = 0;
1061 SortedSet<Node> rev = candidatesStable.descendingSet();
1062 TreeSet<EvaluatedDescriptionPosNeg> cbd = new TreeSet<EvaluatedDescriptionPosNeg>(edComparator);
1063 for(Node eb : rev) {
1064 cbd.add(new EvaluatedDescriptionPosNeg(eb.getConcept(), getSolutionScore(eb.getConcept())));
1065 // return a maximum of 200 elements (we need a maximum, because the
1066 // candidate set can be very large)
1067 if(count > 200)
1068 return cbd;
1069 count++;
1070 }
1071 return cbd;
1072 }
1073
1074 public void printBestSolutions(int nrOfSolutions){
1075 if(!logLevel.equalsIgnoreCase("TRACE")){return;}
1076 if(nrOfSolutions==0)nrOfSolutions=solutions.size();
1077 int i=0;
1078 for(;i<nrOfSolutions; i++) {
1079 Description d = solutions.get(i);
1080 logger.trace(" " + d.toString(baseURI,null) + " (length " + d.getLength() + " " +
1081 "" );
1082 }
1083
1084 }
1085
1086 @Override
1087 public synchronized List<Description> getCurrentlyBestDescriptions(int nrOfSolutions) {
1088 List<Description> best = new LinkedList<Description>();
1089 int i=0;
1090 for(Node n : candidatesStable.descendingSet()) {
1091 best.add(n.getConcept());
1092 if(i==nrOfSolutions)
1093 return best;
1094 i++;
1095 }
1096 return best;
1097 }
1098
1099 // @Override
1100 public ScorePosNeg getSolutionScore() {
1101 return (ScorePosNeg) learningProblem.computeScore(getCurrentlyBestDescription());
1102 }
1103
1104
1105 public ScorePosNeg getSolutionScore(Description d) {
1106 return (ScorePosNeg) learningProblem.computeScore(d);
1107 }
1108
1109 @Override
1110 public void stop() {
1111 stop = true;
1112 }
1113
1114 /**
1115 * @return the startNode
1116 */
1117 public Node getStartNode() {
1118 return startNode;
1119 }
1120
1121 private void handleStoppingConditions(){
1122 solutionFound = (guaranteeXgoodDescriptions() );
1123 solutionFound = (minExecutionTimeReached()&& solutionFound);
1124 if(maxExecutionTimeReached()) { stop();
1125 if(solutions.size()>0)solutionFound = true;
1126 }
1127 }
1128
1129
1130 private boolean guaranteeXgoodDescriptions(){
1131 if(guaranteeXgoodShown)return true;
1132 if(solutions.size()>guaranteeXgoodDescriptions){
1133 logger.info("Minimum number ("+guaranteeXgoodDescriptions+") of good descriptions reached, stopping now...");
1134 guaranteeXgoodShown=true;
1135 return true;}
1136 else return false;
1137
1138 }
1139
1140
1141 private boolean maxExecutionTimeReached(){
1142 if(maxExecutionTimeInSeconds==0)return false;
1143 if(maxExecutionTimeShown)return true;
1144 long needed = System.currentTimeMillis()- this.runtime;
1145 long maxMilliSeconds = maxExecutionTimeInSeconds *1000 ;
1146 if(maxMilliSeconds<needed){
1147 logger.info("Maximum time ("+maxExecutionTimeInSeconds+" seconds) reached, stopping now...");
1148 maxExecutionTimeShown=true;
1149 return true;}
1150 else return false;
1151
1152 }
1153
1154
1155
1156 /**
1157 * true if minExecutionTime reached
1158 * @return true
1159 */
1160 private boolean minExecutionTimeReached(){
1161 if(minExecutionTimeShown)return true;
1162 long needed = System.currentTimeMillis()- this.runtime;
1163 long minMilliSeconds = minExecutionTimeInSeconds *1000 ;
1164 if(minMilliSeconds<needed){
1165 logger.info("Minimum time ("+minExecutionTimeInSeconds+" seconds) reached, stopping when next solution is found");
1166 minExecutionTimeShown=true;
1167 return true;}
1168 else return false;
1169
1170 }
1171
1172 /* (non-Javadoc)
1173 * @see org.dllearner.core.LearningAlgorithm#isRunning()
1174 */
1175 @Override
1176 public boolean isRunning() {
1177 return isRunning;
1178 }
1179
1180 }