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.qtl; 020 021import com.google.common.collect.BiMap; 022import com.google.common.collect.HashBiMap; 023import com.google.common.collect.Sets; 024import org.apache.jena.rdf.model.Model; 025import org.apache.jena.rdf.model.ModelFactory; 026import com.jamonapi.MonitorFactory; 027import gnu.trove.map.TObjectIntMap; 028import gnu.trove.map.hash.TObjectIntHashMap; 029import org.aksw.jena_sparql_api.core.QueryExecutionFactory; 030import org.dllearner.algorithms.qtl.datastructures.impl.EvaluatedRDFResourceTree; 031import org.dllearner.algorithms.qtl.datastructures.impl.QueryTreeImpl.LiteralNodeConversionStrategy; 032import org.dllearner.algorithms.qtl.datastructures.impl.QueryTreeImpl.LiteralNodeSubsumptionStrategy; 033import org.dllearner.algorithms.qtl.datastructures.impl.RDFResourceTree; 034import org.dllearner.algorithms.qtl.heuristics.QueryTreeHeuristic; 035import org.dllearner.algorithms.qtl.heuristics.QueryTreeHeuristicSimple; 036import org.dllearner.algorithms.qtl.impl.QueryTreeFactory; 037import org.dllearner.algorithms.qtl.impl.QueryTreeFactoryBase; 038import org.dllearner.algorithms.qtl.operations.lgg.LGGGenerator; 039import org.dllearner.algorithms.qtl.operations.lgg.LGGGeneratorRDFS; 040import org.dllearner.algorithms.qtl.operations.lgg.LGGGeneratorSimple; 041import org.dllearner.algorithms.qtl.util.Entailment; 042import org.dllearner.core.*; 043import org.dllearner.core.StringRenderer.Rendering; 044import org.dllearner.core.config.ConfigOption; 045import org.dllearner.kb.OWLAPIOntology; 046import org.dllearner.kb.OWLFile; 047import org.dllearner.kb.SparqlEndpointKS; 048import org.dllearner.kb.sparql.ConciseBoundedDescriptionGenerator; 049import org.dllearner.kb.sparql.ConciseBoundedDescriptionGeneratorImpl; 050import org.dllearner.learningproblems.Heuristics; 051import org.dllearner.learningproblems.PosNegLP; 052import org.dllearner.learningproblems.QueryTreeScore; 053import org.semanticweb.owlapi.model.OWLClassExpression; 054import org.semanticweb.owlapi.model.OWLIndividual; 055import org.semanticweb.owlapi.util.SimpleShortFormProvider; 056import org.slf4j.Logger; 057import org.slf4j.LoggerFactory; 058import org.springframework.beans.factory.annotation.Autowired; 059 060import java.io.ByteArrayInputStream; 061import java.io.IOException; 062import java.text.DecimalFormat; 063import java.util.*; 064import java.util.Map.Entry; 065import java.util.concurrent.TimeUnit; 066 067@ComponentAnn(name="query tree learner with noise (disjunctive)", shortName="qtl2dis", version=0.8) 068public class QTL2Disjunctive extends AbstractCELA implements Cloneable{ 069 070 private static final Logger logger = LoggerFactory.getLogger(QTL2Disjunctive.class); 071 private final DecimalFormat dFormat = new DecimalFormat("0.00"); 072 073 private SparqlEndpointKS ks; 074 075// private LGGGenerator2 lggGenerator = new LGGGeneratorSimple(); 076 private LGGGenerator lggGenerator; 077 078 private QueryTreeFactory treeFactory; 079 private ConciseBoundedDescriptionGenerator cbdGen; 080 081 private Queue<EvaluatedRDFResourceTree> todoList; 082 private SortedSet<EvaluatedRDFResourceTree> currentPartialSolutions; 083 084 private double bestCurrentScore = 0d; 085 086 private List<RDFResourceTree> currentPosExampleTrees = new ArrayList<>(); 087 private List<RDFResourceTree> currentNegExampleTrees = new ArrayList<>(); 088 private Set<OWLIndividual> currentPosExamples = new HashSet<>(); 089 private Set<OWLIndividual> currentNegExamples = new HashSet<>(); 090 091 private BiMap<RDFResourceTree, OWLIndividual> tree2Individual = HashBiMap.create(); 092 093 private PosNegLP lp; 094 095 private Model model; 096 097 private volatile boolean stop; 098 private boolean isRunning; 099 100 private List<EvaluatedRDFResourceTree> partialSolutions; 101 102 private EvaluatedDescription<? extends Score> currentBestSolution; 103 104 private QueryTreeHeuristic heuristic; 105 106 //Parameters 107 @ConfigOption(defaultValue="0.0", description="the (approximated) percentage of noise within the examples") 108 private double noisePercentage = 0.0; 109 110 private double coverageWeight = 0.8; 111 private double specifityWeight = 0.1; 112 113 private double minCoveredPosExamplesFraction = 0.2; 114 115 // maximum execution time to compute a part of the solution 116 private double maxTreeComputationTimeInSeconds = 10; 117 118 @ConfigOption(defaultValue = "1", description = "how important it is not to cover negatives") 119 private double beta = 1; 120 121 // minimum score a query tree must have to be part of the solution 122 private double minimumTreeScore = 0.3; 123 124 // If TRUE the algorithm tries to cover all positive examples. Note that 125 // while this improves accuracy on the testing set, 126 // it may lead to overfitting 127 private boolean tryFullCoverage; 128 129 // algorithm will terminate immediately when a correct definition is found 130 private boolean stopOnFirstDefinition; 131 132 // the (approximated) value of noise within the examples 133 private double noise = 0.0; 134 135 private long partialSolutionStartTime; 136 137 private double startPosExamplesSize; 138 private int expressionTests = 0; 139 140 // the time needed until the best solution was found 141 private long timeBestSolutionFound = -1; 142 143 LiteralNodeConversionStrategy[] strategies = new LiteralNodeConversionStrategy[]{ 144 LiteralNodeConversionStrategy.MIN, 145 LiteralNodeConversionStrategy.MAX, 146 LiteralNodeConversionStrategy.MIN_MAX, 147 LiteralNodeConversionStrategy.DATATYPE 148 }; 149 private QueryExecutionFactory qef; 150 151 private Entailment entailment = Entailment.SIMPLE; 152 153 private int maxTreeDepth = 2; 154 155 private boolean useDisjunction = false; 156 157 public QTL2Disjunctive() {} 158 159 public QTL2Disjunctive(PosNegLP learningProblem, AbstractReasonerComponent reasoner) { 160 super(learningProblem, reasoner); 161 loadModel(); 162 } 163 164 public QTL2Disjunctive(PosNegLP lp, QueryExecutionFactory qef) { 165 super.learningProblem = lp; 166 this.lp = lp; 167 this.qef = qef; 168 } 169 170 public QTL2Disjunctive(PosNegLP lp, SparqlEndpointKS ks) { 171 this(lp, ks.getQueryExecutionFactory()); 172 } 173 174// public QTL2Disjunctive(PosNegLP lp, Model model) { 175// this.learningProblem = lp; 176// this.model = model; 177// } 178 179 /** 180 * Copy constructor. 181 * @param qtl the QTL2Disjunctive instance 182 */ 183 public QTL2Disjunctive(QTL2Disjunctive qtl) { 184 super(qtl.getLearningProblem(), qtl.getReasoner()); 185 this.model = ModelFactory.createDefaultModel(); 186 this.model.add(qtl.model); 187 this.beta = qtl.beta; 188 this.maxExecutionTimeInSeconds = qtl.maxExecutionTimeInSeconds; 189 this.maxTreeComputationTimeInSeconds = qtl.maxTreeComputationTimeInSeconds; 190 this.tryFullCoverage = qtl.tryFullCoverage; 191 this.stopOnFirstDefinition = qtl.stopOnFirstDefinition; 192 } 193 194 /* (non-Javadoc) 195 * @see org.dllearner.core.Component#init() 196 */ 197 @Override 198 public void init() throws ComponentInitException { 199 logger.info("Initializing..."); 200 if(!(learningProblem instanceof PosNegLP)){ 201 throw new IllegalArgumentException("Only PosNeg learning problems are supported"); 202 } 203 lp = (PosNegLP) learningProblem; 204 205 // get query execution factory from KS 206 if(qef == null) { 207 qef = ks.getQueryExecutionFactory(); 208 } 209 210 if(treeFactory == null) { 211 treeFactory = new QueryTreeFactoryBase(); 212 } 213 cbdGen = new ConciseBoundedDescriptionGeneratorImpl(qef); 214 215 // set the used heuristic 216 if(heuristic == null){ 217 heuristic = new QueryTreeHeuristicSimple(); 218 heuristic.setPosExamplesWeight(beta); 219 } 220 221 if(entailment == Entailment.SIMPLE) { 222 lggGenerator = new LGGGeneratorSimple(); 223 } else if(entailment == Entailment.RDFS){ 224 lggGenerator = new LGGGeneratorRDFS(reasoner); 225 } 226 227 // generate the query trees 228 generateQueryTrees(); 229 230 startPosExamplesSize = currentPosExampleTrees.size(); 231 232 //console rendering of class expressions 233 StringRenderer.setRenderer(Rendering.MANCHESTER_SYNTAX); 234 StringRenderer.setShortFormProvider(new SimpleShortFormProvider()); 235 236 //compute the LGG for all examples 237 //this allows us to prune all other trees because we can omit paths in trees which are contained in all positive 238 //as well as negative examples 239// List<RDFResourceTree> allExamplesTrees = new ArrayList<RDFResourceTree>(); 240// allExamplesTrees.addAll(currentPosExampleTrees); 241// allExamplesTrees.addAll(currentNegExampleTrees); 242// RDFResourceTree lgg = lggGenerator.getLGG(allExamplesTrees); 243// lgg.dump(); 244 245 initialized = true; 246 logger.info("...initialization finished."); 247 } 248 249 /** 250 * @param entailment the entailment to set 251 */ 252 public void setEntailment(Entailment entailment) { 253 this.entailment = entailment; 254 } 255 256 private void generateQueryTrees(){ 257 logger.info("Generating trees..."); 258 RDFResourceTree queryTree; 259 260 // positive examples 261 if(currentPosExampleTrees.isEmpty()){ 262 for (OWLIndividual ind : lp.getPositiveExamples()) { 263 try { 264 Model cbd = cbdGen.getConciseBoundedDescription(ind.toStringID(), maxTreeDepth); 265// cbd.write(new FileOutputStream("/tmp/dbpedia-" + ind.toStringID().substring(ind.toStringID().lastIndexOf('/') + 1) + ".ttl"), "TURTLE", null); 266 queryTree = treeFactory.getQueryTree(ind.toStringID(), cbd, maxTreeDepth); 267 tree2Individual.put(queryTree, ind); 268 currentPosExampleTrees.add(queryTree); 269 currentPosExamples.add(ind); 270 logger.debug(ind.toStringID()); 271 logger.debug(queryTree.getStringRepresentation()); 272 } catch (Exception e) { 273 logger.error("Failed to generate tree for resource " + ind, e); 274 throw new RuntimeException(); 275 } 276 } 277 } 278 279 // negative examples 280 if(currentNegExampleTrees.isEmpty()){ 281 for (OWLIndividual ind : lp.getNegativeExamples()) { 282 try { 283 Model cbd = cbdGen.getConciseBoundedDescription(ind.toStringID(), maxTreeDepth); 284 queryTree = treeFactory.getQueryTree(ind.toStringID(), cbd, maxTreeDepth); 285 tree2Individual.put(queryTree, ind); 286 currentNegExampleTrees.add(queryTree); 287 currentNegExamples.add(ind); 288 logger.debug(ind.toStringID()); 289 logger.debug(queryTree.getStringRepresentation()); 290 } catch (Exception e) { 291 logger.error("Failed to generate tree for resource " + ind, e); 292 throw new RuntimeException(); 293 } 294 } 295 } 296 logger.info("...done."); 297 } 298 299 /* (non-Javadoc) 300 * @see org.dllearner.core.LearningAlgorithm#start() 301 */ 302 @Override 303 public void start() { 304 305 if(currentPosExampleTrees.isEmpty()) { 306 logger.info("No positive examples given!"); 307 return; 308 } 309 310 printSetup(); 311 logger.info("Running..."); 312 313 reset(); 314 315 int i = 1; 316 while(!terminationCriteriaSatisfied() && (useDisjunction || i == 1)){ 317 logger.info(i++ + ". iteration..."); 318 logger.info("#Remaining pos. examples:" + currentPosExampleTrees.size()); 319 logger.info("#Remaining neg. examples:" + currentNegExampleTrees.size()); 320 321 // compute best (partial) solution computed so far 322 EvaluatedRDFResourceTree bestPartialSolution = computeBestPartialSolution(); 323 324 // add to set of partial solutions if criteria are satisfied 325 if(bestPartialSolution.getScore() >= minimumTreeScore){ 326 327 partialSolutions.add(bestPartialSolution); 328 329 // remove all examples covered by current partial solution 330 RDFResourceTree tree; 331 for (Iterator<RDFResourceTree> iterator = currentPosExampleTrees.iterator(); iterator.hasNext();) { 332 tree = iterator.next(); 333 if(!bestPartialSolution.getFalseNegatives().contains(tree)){//a pos tree that is not covered 334 iterator.remove(); 335 currentPosExamples.remove(tree2Individual.get(tree)); 336 } 337 } 338 for (Iterator<RDFResourceTree> iterator = currentNegExampleTrees.iterator(); iterator.hasNext();) { 339 tree = iterator.next(); 340 if(bestPartialSolution.getFalsePositives().contains(tree)){//a neg example that is covered 341 iterator.remove(); 342 currentNegExamples.remove(tree2Individual.get(tree)); 343 } 344 } 345 346 // (re)build the current combined solution from all partial solutions 347 currentBestSolution = buildCombinedSolution(); 348 349 logger.info("combined accuracy: " + dFormat.format(currentBestSolution.getAccuracy())); 350 } else { 351 String message = "No partial tree found which satisfies the minimal criteria."; 352 if(currentBestSolution != null) { 353 message += "- the best was: " 354 + currentBestSolution.getDescription() 355 + " with score " + currentBestSolution.getScore(); 356 } 357 logger.info(message); 358 } 359 360 } 361 362 isRunning = false; 363 364 postProcess(); 365 366 long nanoEndTime = System.nanoTime(); 367 logger.info("Finished in " + TimeUnit.NANOSECONDS.toMillis(nanoEndTime - nanoStartTime) + "ms."); 368 logger.info(expressionTests +" descriptions tested"); 369 if(currentBestSolution != null) { 370 logger.info("Combined solution:" + currentBestSolution.getDescription().toString().replace("\n", "")); 371 logger.info(currentBestSolution.getScore().toString()); 372 } else { 373 logger.info("Could not find a solution in the given time."); 374 } 375 } 376 377 /** 378 * This method can be called for clean up of the solutions and re-ranking. 379 */ 380 private void postProcess() { 381 logger.trace("Post processing ..."); 382 // pick solutions with same accuracy, i.e. in the pos only case 383 // covering the same number of positive examples 384 SortedSet<EvaluatedRDFResourceTree> solutions = getSolutions(); 385 // pick solutions with accuracy above 386 // mas(maximum achievable score) - noise 387 List<EvaluatedRDFResourceTree> solutionsForPostProcessing = new ArrayList<>(); 388 for (EvaluatedRDFResourceTree solution : solutions) { 389 390 double accuracy = solution.getTreeScore().getAccuracy(); 391 392 double mas = heuristic.getMaximumAchievableScore(solution); 393 394 double epsilon = 0.01; 395 396 if(accuracy != mas && accuracy >= (mas - noise - epsilon)) { 397 solutionsForPostProcessing.add(solution); 398 } 399 } 400 401 logger.trace("Finished post processing."); 402 } 403 404 /** 405 * Compute a (partial) solution that covers as much positive examples as possible. 406 * @return a (partial) solution 407 */ 408 private EvaluatedRDFResourceTree computeBestPartialSolution(){ 409 logger.info("Computing best partial solution..."); 410 bestCurrentScore = Double.NEGATIVE_INFINITY; 411 partialSolutionStartTime = System.currentTimeMillis(); 412 initTodoList(currentPosExampleTrees, currentNegExampleTrees); 413 414 EvaluatedRDFResourceTree bestPartialSolutionTree = null; 415 EvaluatedRDFResourceTree currentElement; 416 RDFResourceTree currentTree; 417 418 // generate id for each pos and neg example tree 419 TObjectIntMap<RDFResourceTree> index = new TObjectIntHashMap<>(this.currentPosExampleTrees.size() + this.currentNegExampleTrees.size()); 420 int id = 1; 421 for (RDFResourceTree posTree : currentPosExampleTrees) { 422 index.put(posTree, id++); 423 } 424 Set<Set<RDFResourceTree>> processedCombinations = new HashSet<>(); 425 426 while(!partialSolutionTerminationCriteriaSatisfied()){ 427 logger.trace("ToDo list size: " + todoList.size()); 428 // pick best element from todo list 429 currentElement = todoList.poll(); 430 currentTree = currentElement.getTree(); 431 432 logger.trace("Next tree: {} ({})", currentElement.getBaseQueryTrees(), currentElement.getTreeScore()); 433 434 // generate the LGG between the chosen tree and each false negative resp. uncovered positive example 435 Collection<RDFResourceTree> falseNegatives = currentElement.getFalseNegatives(); 436 437 if(falseNegatives.isEmpty()) { // if the current solution covers already all pos examples 438// addToSolutions(bestPartialSolutionTree); 439// bestPartialSolutionTree = currentElement; 440 } 441 442 Iterator<RDFResourceTree> it = falseNegatives.iterator(); 443 while (it.hasNext() && !(useDisjunction && isPartialSolutionTimeExpired()) && !isTimeExpired()) { 444 RDFResourceTree uncoveredTree = it.next(); 445 logger.trace("Uncovered tree: " + uncoveredTree); 446 447 // we should avoid the computation of lgg(t2,t1) if we already did lgg(t1,t2) 448 Set<RDFResourceTree> baseQueryTrees = Sets.newTreeSet(currentElement.getBaseQueryTrees()); 449 baseQueryTrees.add(uncoveredTree); 450// String s = ""; 451// for (RDFResourceTree queryTree : baseQueryTrees) { 452// s += index.get(queryTree) + ","; 453// } 454// System.err.println(s); 455 if(!processedCombinations.add(baseQueryTrees)) { 456// System.err.println("skipping"); 457// continue; 458 } 459 460 // compute the LGG 461 MonitorFactory.getTimeMonitor("lgg").start(); 462 ((LGGGeneratorSimple)lggGenerator).setTimeout(getRemainingPartialSolutionTime(), TimeUnit.SECONDS); 463 RDFResourceTree lgg = lggGenerator.getLGG(currentTree, uncoveredTree); 464 MonitorFactory.getTimeMonitor("lgg").stop(); 465// System.out.println("COMPLETE:" + ((LGGGeneratorSimple)lggGenerator).isComplete()); 466// logger.info("LGG: " + lgg.getStringRepresentation()); 467 468 // redundancy check 469 boolean redundant = isRedundant(lgg); 470 if(redundant) { 471 logger.trace("redundant"); 472 continue; 473 } 474 475 // evaluate the LGG 476 Set<EvaluatedRDFResourceTree> solutions = evaluate(lgg, true); 477 for (EvaluatedRDFResourceTree solution : solutions) { 478 solution.setBaseQueryTrees(baseQueryTrees); 479 logger.trace("solution: {} ({})", solution.getBaseQueryTrees(), solution.getTreeScore()); 480 expressionTests++; 481 double score = solution.getScore(); 482 double mas = heuristic.getMaximumAchievableScore(solution); 483 484 if(score >= bestCurrentScore){ 485 if(score > bestCurrentScore){ 486 timeBestSolutionFound = getCurrentRuntimeInMilliSeconds(); 487 logger.info("\tGot better solution after {}ms:" + solution.getTreeScore(), timeBestSolutionFound); 488 logger.info("\t" + solutionAsString(solution.asEvaluatedDescription())); 489 bestCurrentScore = score; 490 bestPartialSolutionTree = solution; 491 } 492 // add to ToDo list, if not already contained in ToDo list or solution list 493 if(bestCurrentScore == 1.0 || mas > score){ 494// todo(solution); 495 } 496 } else if(bestCurrentScore == 1.0 || mas >= bestCurrentScore){ // add to ToDo list if max. achievable score is higher 497// todo(solution); 498 } else { 499 logger.trace("Too weak: {}", solution.getTreeScore()); 500// System.err.println(solution.getEvaluatedDescription()); 501// System.out.println("Too general"); 502// System.out.println("MAS=" + mas + "\nBest=" + bestCurrentScore); 503// todo(solution); 504 } 505 todo(solution); 506 addToSolutions(solution); 507 } 508 } 509// addToSolutions(currentElement); 510 } 511 512 long endTime = System.currentTimeMillis(); 513 logger.info("...finished computing best partial solution in " + (endTime-partialSolutionStartTime) + "ms."); 514 EvaluatedDescription bestPartialSolution = bestPartialSolutionTree.asEvaluatedDescription(); 515 516 logger.info("Best partial solution: " + solutionAsString(bestPartialSolution) + "\n(" + bestPartialSolution.getScore() + ")"); 517 518 logger.trace("LGG time: " + MonitorFactory.getTimeMonitor("lgg").getTotal() + "ms"); 519 logger.trace("Avg. LGG time: " + MonitorFactory.getTimeMonitor("lgg").getAvg() + "ms"); 520 logger.info("#LGG computations: " + MonitorFactory.getTimeMonitor("lgg").getHits()); 521 522 logger.trace("Subsumption test time: " + MonitorFactory.getTimeMonitor("subsumption").getTotal() + "ms"); 523 logger.trace("Avg. subsumption test time: " + MonitorFactory.getTimeMonitor("subsumption").getAvg() + "ms"); 524 logger.trace("#Subsumption tests: " + MonitorFactory.getTimeMonitor("subsumption").getHits()); 525 526 return bestPartialSolutionTree; 527 } 528 529 private String solutionAsString(EvaluatedDescription ed) { 530 return renderer.render(ed.getDescription()).replace("\n", "").replaceAll("\\\\s{2,}", " "); 531 } 532 533 private boolean addToSolutions(EvaluatedRDFResourceTree solution) { 534 for (EvaluatedRDFResourceTree partialSolution : currentPartialSolutions) { 535 if(QueryTreeUtils.sameTrees(partialSolution.getTree(), solution.getTree())) { 536 return false; 537 } 538 } 539 return currentPartialSolutions.add(solution); 540 } 541 542 /** 543 * Initializes the ToDo list with all distinct trees contained in the given list of positive 544 * example trees {@code posExamples} and negative example trees {@code negExamples}. 545 * First, distinct trees are computed and afterwards, for each tree an initial score will be 546 * computed. 547 * @param posExamples the positive example trees 548 * @param negExamples the negative example trees 549 */ 550 private void initTodoList(List<RDFResourceTree> posExamples, List<RDFResourceTree> negExamples){ 551 todoList = new PriorityQueue<>(); 552 currentPartialSolutions = new TreeSet<>(); 553// EvaluatedRDFResourceTree dummy = new EvaluatedRDFResourceTree(new QueryTreeImpl<String>((N)"TOP"), trees, 0d); 554// todoList.add(dummy); 555 556 // compute distinct trees, i.e. check if some of the trees already cover others 557 Collection<RDFResourceTree> distinctTrees = new ArrayList<>(); 558 for (RDFResourceTree queryTree : posExamples) { 559 boolean distinct = true; 560 for (RDFResourceTree otherTree : distinctTrees) { 561 if(!queryTree.equals(otherTree)){ 562 if(QueryTreeUtils.sameTrees(queryTree, otherTree)){ 563 distinct = false; 564 break; 565 } 566 } 567 } 568 if(distinct){ 569 distinctTrees.add(queryTree); 570 } 571 } 572 573 // compute an initial score 574 for (RDFResourceTree queryTree : distinctTrees) { 575 EvaluatedRDFResourceTree evaluatedQueryTree = evaluateSimple(queryTree, false); 576 evaluatedQueryTree.setBaseQueryTrees(Collections.singleton(queryTree)); 577 todoList.add(evaluatedQueryTree); 578 } 579 } 580 581 /** 582 * @return TRUE if the query tree is already contained in the solutions or 583 * todo list, otherwise FALSE 584 */ 585 private boolean isRedundant(RDFResourceTree tree) { 586 //check if not already contained in todo list 587 for (EvaluatedRDFResourceTree evTree : todoList) { 588 if(QueryTreeUtils.sameTrees(tree, evTree.getTree())){ 589 logger.trace("Not added to TODO list: Already contained in."); 590// logger.trace(evTree.getBaseQueryTrees().toString()); 591 return true; 592 } 593 } 594 595 //check if not already contained in solutions 596 for (EvaluatedRDFResourceTree evTree : currentPartialSolutions) { 597 if(QueryTreeUtils.sameTrees(tree, evTree.getTree())){ 598 logger.trace("Not added to partial solutions list: Already contained in."); 599 return true; 600 } 601 } 602 return false; 603 } 604 605 /** 606 * Add tree to ToDo list if not already contained in that list or the solutions. 607 * @param solution the solution 608 */ 609 private void todo(EvaluatedRDFResourceTree solution){ 610 logger.trace("Added to TODO list."); 611 todoList.add(solution); 612 } 613 614 private EvaluatedRDFResourceTree evaluateSimple(RDFResourceTree tree, boolean useSpecifity){ 615 //1. get a score for the coverage = recall oriented 616 //compute positive examples which are not covered by LGG 617 List<RDFResourceTree> uncoveredPositiveExampleTrees = getUncoveredTrees(tree, currentPosExampleTrees); 618 Set<OWLIndividual> uncoveredPosExamples = new TreeSet<>(); 619 for (RDFResourceTree queryTree : uncoveredPositiveExampleTrees) { 620 uncoveredPosExamples.add(tree2Individual.get(queryTree)); 621 } 622 //compute negative examples which are covered by LGG 623 Collection<RDFResourceTree> coveredNegativeExampleTrees = getCoveredTrees(tree, currentNegExampleTrees); 624 Set<OWLIndividual> coveredNegExamples = new TreeSet<>(); 625 for (RDFResourceTree queryTree : coveredNegativeExampleTrees) { 626 coveredNegExamples.add(tree2Individual.get(queryTree)); 627 } 628 //compute score 629 int coveredPositiveExamples = currentPosExampleTrees.size() - uncoveredPositiveExampleTrees.size(); 630 double recall = coveredPositiveExamples / (double)currentPosExampleTrees.size(); 631 double precision = (coveredNegativeExampleTrees.size() + coveredPositiveExamples == 0) 632 ? 0 633 : coveredPositiveExamples / (double)(coveredPositiveExamples + coveredNegativeExampleTrees.size()); 634 635 double coverageScore = Heuristics.getFScore(recall, precision, beta); 636 637 //2. get a score for the specifity of the query, i.e. how many edges/nodes = precision oriented 638 int nrOfSpecificNodes = 0; 639 for (RDFResourceTree childNode : QueryTreeUtils.getNodes(tree)) { 640 if(!childNode.isVarNode()){ 641 nrOfSpecificNodes++; 642 } 643 } 644 double specifityScore = 0d; 645 if(useSpecifity){ 646 specifityScore = Math.log(nrOfSpecificNodes); 647 } else { 648 specifityScore = 1 / (double) nrOfSpecificNodes; 649 } 650 651 //3.compute the total score 652 double score = coverageWeight * coverageScore + specifityWeight * specifityScore; 653 654 QueryTreeScore queryTreeScore = new QueryTreeScore(score, coverageScore, 655 new TreeSet<>(Sets.difference(currentPosExamples, uncoveredPosExamples)), uncoveredPosExamples, 656 coveredNegExamples, new TreeSet<>(Sets.difference(currentNegExamples, coveredNegExamples)), 657 specifityScore, nrOfSpecificNodes); 658 659// QueryTreeScore queryTreeScore = new QueryTreeScore(score, coverageScore, 660// null,null,null,null, 661// specifityScore, nrOfSpecificNodes); 662 663 EvaluatedRDFResourceTree evaluatedTree = new EvaluatedRDFResourceTree(tree, uncoveredPositiveExampleTrees, coveredNegativeExampleTrees, queryTreeScore); 664 665 //TODO use only the heuristic to compute the score 666 score = heuristic.getScore(evaluatedTree); 667 queryTreeScore.setScore(score); 668 queryTreeScore.setAccuracy(score); 669 670 return evaluatedTree; 671 } 672 673 /** 674 * Evaluated a query tree such that it returns a set of evaluated query trees. 675 * A set is returned because there are several ways how to convert literal nodes. 676 * @param tree the query tree 677 * @param useSpecifity whether to use SPECIFITY as measure 678 * @return a set of evaluated query trees 679 */ 680 private Set<EvaluatedRDFResourceTree> evaluate(RDFResourceTree tree, boolean useSpecifity){ 681 Set<EvaluatedRDFResourceTree> evaluatedTrees = new TreeSet<>(); 682 683 LiteralNodeSubsumptionStrategy[] strategies = LiteralNodeSubsumptionStrategy.values(); 684 strategies = new LiteralNodeSubsumptionStrategy[]{ 685 LiteralNodeSubsumptionStrategy.DATATYPE, 686// LiteralNodeSubsumptionStrategy.INTERVAL, 687// LiteralNodeSubsumptionStrategy.MIN, 688// LiteralNodeSubsumptionStrategy.MAX, 689 }; 690 for (LiteralNodeSubsumptionStrategy strategy : strategies) { 691 // 1. get a score for the coverage = recall oriented 692 List<RDFResourceTree> uncoveredPositiveExampleTrees = new ArrayList<>(); 693 List<RDFResourceTree> coveredNegativeExampleTrees = new ArrayList<>(); 694 695 // compute positive examples which are not covered by LGG 696 for (RDFResourceTree posTree : currentPosExampleTrees) { 697// System.out.print(currentPosExampleTrees.indexOf(posTree) + ":"); 698 if(!QueryTreeUtils.isSubsumedBy(posTree, tree, entailment, reasoner)){ 699// System.err.println(posTree.getStringRepresentation(true));System.err.println(tree.getStringRepresentation(true)); 700// System.out.println("FALSE"); 701 uncoveredPositiveExampleTrees.add(posTree); 702 } else { 703// System.out.println("TRUE"); 704 } 705 } 706 707 // compute negative examples which are covered by LGG 708 for (RDFResourceTree negTree : currentNegExampleTrees) { 709 if(QueryTreeUtils.isSubsumedBy(negTree, tree, entailment, reasoner)){ 710 coveredNegativeExampleTrees.add(negTree); 711 } 712 } 713 714 // convert to individuals 715 Set<OWLIndividual> uncoveredPosExamples = asIndividuals(uncoveredPositiveExampleTrees); 716 Set<OWLIndividual> coveredNegExamples = asIndividuals(coveredNegativeExampleTrees); 717 718 // compute score 719 int coveredPositiveExamples = currentPosExampleTrees.size() - uncoveredPositiveExampleTrees.size(); 720 double recall = coveredPositiveExamples / (double)currentPosExampleTrees.size(); 721 double precision = (coveredNegativeExampleTrees.size() + coveredPositiveExamples == 0) 722 ? 0 723 : coveredPositiveExamples / (double)(coveredPositiveExamples + coveredNegativeExampleTrees.size()); 724 725 double coverageScore = Heuristics.getFScore(recall, precision, beta); 726 727 // 2. get a score for the specifity of the query, i.e. how many edges/nodes = precision oriented 728 int nrOfSpecificNodes = 0; 729 for (RDFResourceTree childNode : QueryTreeUtils.getNodes(tree)) { 730 if(!childNode.isVarNode()){ 731 nrOfSpecificNodes++; 732 } 733 } 734 double specifityScore = 0d; 735 if(useSpecifity){ 736 specifityScore = Math.log(nrOfSpecificNodes); 737 } 738 739 // 3.compute the total score 740 double score = coverageWeight * coverageScore + specifityWeight * specifityScore; 741 742 QueryTreeScore queryTreeScore = new QueryTreeScore(score, coverageScore, 743 new TreeSet<>(Sets.difference(currentPosExamples, uncoveredPosExamples)), uncoveredPosExamples, 744 coveredNegExamples, new TreeSet<>(Sets.difference(currentNegExamples, coveredNegExamples)), 745 specifityScore, nrOfSpecificNodes); 746 747 EvaluatedRDFResourceTree evaluatedTree = new EvaluatedRDFResourceTree(tree, uncoveredPositiveExampleTrees, coveredNegativeExampleTrees, queryTreeScore); 748 749 //TODO use only the heuristic to compute the score 750 score = heuristic.getScore(evaluatedTree); 751 queryTreeScore.setScore(score); 752 queryTreeScore.setAccuracy(score); 753 754 evaluatedTrees.add(evaluatedTree); 755 } 756 757 return evaluatedTrees; 758 } 759 760 /** 761 * Evaluated a query tree such that it returns a set of evaluated query trees. 762 * A set is returned because there are several ways how to convert literal nodes. 763 * @param tree the query tree 764 * @param useSpecifity whether to use SPECIFITY as measure 765 * @return a set of evaluated query trees 766 */ 767 private Set<EvaluatedRDFResourceTree> evaluate2(RDFResourceTree tree, boolean useSpecifity){ 768 Set<EvaluatedRDFResourceTree> evaluatedTrees = new TreeSet<>(); 769 770 //test different strategies on the conversion of literal nodes 771 Set<OWLClassExpression> combinations = new HashSet<>(); 772 773 for (LiteralNodeConversionStrategy strategy : strategies) { 774 OWLClassExpression ce = QueryTreeUtils.toOWLClassExpression(tree); 775 combinations.add(ce); 776 } 777 //compute all combinations of different types of facets 778// OWLClassExpression ce = tree.asOWLClassExpression(LiteralNodeConversionStrategy.FACET_RESTRICTION); 779// combinations = ce.accept(new ClassExpressionLiteralCombination()); 780 for (OWLClassExpression c : combinations) { 781 //convert to individuals 782 SortedSet<OWLIndividual> coveredExamples = reasoner.getIndividuals(c); 783 Set<OWLIndividual> coveredPosExamples = new TreeSet<>(Sets.intersection(currentPosExamples, coveredExamples)); 784 Set<OWLIndividual> uncoveredPosExamples = new TreeSet<>(Sets.difference(currentPosExamples, coveredExamples)); 785 Set<OWLIndividual> coveredNegExamples = new TreeSet<>(Sets.intersection(currentNegExamples, coveredExamples)); 786 Set<OWLIndividual> uncoveredNegExamples = new TreeSet<>(Sets.difference(currentNegExamples, coveredExamples)); 787 788 //compute score 789 double recall = coveredPosExamples.size() / (double)currentPosExamples.size(); 790 double precision = (coveredNegExamples.size() + coveredPosExamples.size() == 0) 791 ? 0 792 : coveredPosExamples.size() / (double)(coveredPosExamples.size() + coveredNegExamples.size()); 793 794 double coverageScore = Heuristics.getFScore(recall, precision, beta); 795 796 //2. get a score for the specificity of the query, i.e. how many edges/nodes = precision oriented 797 int nrOfSpecificNodes = 0; 798 for (RDFResourceTree childNode : QueryTreeUtils.getNodes(tree)){ 799 if(!childNode.isVarNode()){ 800 nrOfSpecificNodes++; 801 } 802 } 803 double specifityScore = 0d; 804 if(useSpecifity){ 805 specifityScore = Math.log(nrOfSpecificNodes); 806 } 807 808 //3.compute the total score 809 double score = coverageWeight * coverageScore + specifityWeight * specifityScore; 810 811 QueryTreeScore queryTreeScore = new QueryTreeScore( 812 score, coverageScore, 813 coveredPosExamples, uncoveredPosExamples, 814 coveredNegExamples, uncoveredNegExamples, 815 specifityScore, nrOfSpecificNodes); 816 817 //TODO use only the heuristic to compute the score 818 EvaluatedRDFResourceTree evaluatedTree = new EvaluatedRDFResourceTree(tree, 819 asQueryTrees(uncoveredPosExamples), asQueryTrees(coveredNegExamples), queryTreeScore); 820 score = heuristic.getScore(evaluatedTree); 821 queryTreeScore.setScore(score); 822 queryTreeScore.setAccuracy(score); 823 824 825 EvaluatedDescription evaluatedDescription = new EvaluatedDescription(c, queryTreeScore); 826 827 evaluatedTree.setDescription(evaluatedDescription); 828 829 evaluatedTrees.add(evaluatedTree); 830 } 831 return evaluatedTrees; 832 } 833 834 private EvaluatedDescription<? extends Score> buildCombinedSolution(){ 835 EvaluatedDescription<? extends Score> bestCombinedSolution = null; 836 double bestScore = Double.NEGATIVE_INFINITY; 837 LiteralNodeConversionStrategy[] strategies = LiteralNodeConversionStrategy.values(); 838 strategies = new LiteralNodeConversionStrategy[]{LiteralNodeConversionStrategy.DATATYPE}; 839 for (LiteralNodeConversionStrategy strategy : strategies) { 840 EvaluatedDescription<? extends Score> combinedSolution; 841 if(partialSolutions.size() == 1){ 842 combinedSolution = partialSolutions.get(0).asEvaluatedDescription(); 843 } else { 844 Set<OWLClassExpression> disjuncts = new TreeSet<>(); 845 846 Set<OWLIndividual> posCovered = new HashSet<>(); 847 Set<OWLIndividual> negCovered = new HashSet<>(); 848 849 //build the union of all class expressions 850 OWLClassExpression partialDescription; 851 for (EvaluatedRDFResourceTree partialSolution : partialSolutions) { 852 partialDescription = partialSolution.asEvaluatedDescription().getDescription(); 853 disjuncts.add(partialDescription); 854 posCovered.addAll(partialSolution.getTreeScore().getCoveredPositives()); 855 negCovered.addAll(partialSolution.getTreeScore().getCoveredNegatives()); 856 } 857 OWLClassExpression unionDescription = dataFactory.getOWLObjectUnionOf(disjuncts); 858 859 Set<OWLIndividual> posNotCovered = Sets.difference(lp.getPositiveExamples(), posCovered); 860 Set<OWLIndividual> negNotCovered = Sets.difference(lp.getNegativeExamples(), negCovered); 861 862 //compute the coverage 863 double recall = posCovered.size() / (double)lp.getPositiveExamples().size(); 864 double precision = (posCovered.size() + negCovered.size() == 0) 865 ? 0 866 : posCovered.size() / (double)(posCovered.size() + negCovered.size()); 867 868 double coverageScore = Heuristics.getFScore(recall, precision, beta); 869 870// ScoreTwoValued score = new ScoreTwoValued(posCovered, posNotCovered, negCovered, negNotCovered); 871// score.setAccuracy(coverageScore); 872 QueryTreeScore score = new QueryTreeScore(coverageScore, coverageScore, posCovered, posNotCovered, negCovered, negNotCovered, -1, -1); 873 874 combinedSolution = new EvaluatedDescription(unionDescription, score); 875 } 876 if(combinedSolution.getAccuracy() > bestScore){ 877 bestCombinedSolution = combinedSolution; 878 bestCurrentScore = combinedSolution.getAccuracy(); 879 } 880 } 881 return bestCombinedSolution; 882 } 883 884 private void reset(){ 885 stop = false; 886 isRunning = true; 887 888 currentBestSolution = null; 889 partialSolutions = new ArrayList<>(); 890 891 bestCurrentScore = minimumTreeScore; 892 893 MonitorFactory.getTimeMonitor("lgg").reset(); 894 nanoStartTime = System.nanoTime(); 895 } 896 897 /* (non-Javadoc) 898 * @see org.dllearner.core.StoppableLearningAlgorithm#stop() 899 */ 900 @Override 901 public void stop() { 902 stop = true; 903 } 904 905 /* (non-Javadoc) 906 * @see org.dllearner.core.AbstractCELA#getCurrentlyBestDescription() 907 */ 908 @Override 909 public OWLClassExpression getCurrentlyBestDescription() { 910 return currentBestSolution.getDescription(); 911 } 912 913 /* (non-Javadoc) 914 * @see org.dllearner.core.AbstractCELA#getCurrentlyBestEvaluatedDescription() 915 */ 916 @Override 917 public EvaluatedDescription getCurrentlyBestEvaluatedDescription() { 918 return currentBestSolution; 919 } 920 921 /* (non-Javadoc) 922 * @see org.dllearner.core.StoppableLearningAlgorithm#isRunning() 923 */ 924 @Override 925 public boolean isRunning() { 926 return isRunning; 927 } 928 929// @Autowired 930// public void setLearningProblem(PosNegLP learningProblem) { 931// this.lp = learningProblem; 932// } 933 934// @Autowired 935 @Override 936 public void setReasoner(AbstractReasonerComponent reasoner){ 937 super.setReasoner(reasoner); 938// loadModel(); 939 } 940 941 private void loadModel(){ 942 model = ModelFactory.createDefaultModel(); 943 for (KnowledgeSource ks : reasoner.getSources()) { 944 if(ks instanceof OWLFile){ 945 try { 946 model.read(((OWLFile) ks).getURL().openStream(), null); 947 } catch (IOException e) { 948 e.printStackTrace(); 949 } 950 } else if(ks instanceof OWLAPIOntology){ 951 ByteArrayInputStream bais = new ByteArrayInputStream(((OWLAPIOntology) ks).getConverter().convert(((OWLAPIOntology) ks).getOntology())); 952 model.read(bais, null); 953 try { 954 bais.close(); 955 } catch (IOException e) { 956 e.printStackTrace(); 957 } 958 } 959 } 960 } 961 962 private Set<OWLIndividual> asIndividuals(Collection<RDFResourceTree> trees){ 963 Set<OWLIndividual> individuals = new HashSet<>(trees.size()); 964 for (RDFResourceTree queryTree : trees) { 965 individuals.add(tree2Individual.get(queryTree)); 966 } 967 return individuals; 968 } 969 970 private Set<RDFResourceTree> asQueryTrees(Collection<OWLIndividual> individuals){ 971 Set<RDFResourceTree> trees = new HashSet<>(individuals.size()); 972 for (OWLIndividual ind : individuals) { 973 trees.add(tree2Individual.inverse().get(ind)); 974 } 975 return trees; 976 } 977 978 /** 979 * Computes all trees from the given list {@code allTrees} which are subsumed by {@code tree}. 980 * @param tree the tree 981 * @param trees all trees 982 * @return all trees from the given list {@code allTrees} which are subsumed by {@code tree} 983 */ 984 private List<RDFResourceTree> getCoveredTrees(RDFResourceTree tree, List<RDFResourceTree> trees){ 985 List<RDFResourceTree> coveredTrees = new ArrayList<>(); 986 for (RDFResourceTree queryTree : trees) { 987 if(QueryTreeUtils.isSubsumedBy(queryTree, tree)){ 988 coveredTrees.add(queryTree); 989 } 990 } 991 return coveredTrees; 992 } 993 994 /** 995 * Computes all trees from the given list {@code trees} which are not subsumed by {@code tree}. 996 * @param tree the tree 997 * @param trees the trees 998 * @return all trees from the given list {@code trees} which are not subsumed by {@code tree}. 999 */ 1000 private List<RDFResourceTree> getUncoveredTrees(RDFResourceTree tree, List<RDFResourceTree> trees){ 1001 List<RDFResourceTree> uncoveredTrees = new ArrayList<>(); 1002 for (RDFResourceTree queryTree : trees) { 1003 if(!QueryTreeUtils.isSubsumedBy(queryTree, tree)){ 1004 uncoveredTrees.add(queryTree); 1005 } 1006 } 1007 return uncoveredTrees; 1008 } 1009 1010 private boolean terminationCriteriaSatisfied() { 1011 //stop was called or time expired 1012 if(stop || isTimeExpired()){ 1013 return true; 1014 } 1015 1016 // stop if there are no more positive examples to cover 1017 if (stopOnFirstDefinition && currentPosExamples.isEmpty()) { 1018 return true; 1019 } 1020 1021 // we stop when the score of the last tree added is too low 1022 // (indicating that the algorithm could not find anything appropriate 1023 // in the timeframe set) 1024 if (bestCurrentScore < minimumTreeScore) { 1025 return true; 1026 } 1027 1028 // stop when almost all positive examples have been covered 1029 if (tryFullCoverage) { 1030 return false; 1031 } else { 1032 int maxPosRemaining = (int) Math.ceil(startPosExamplesSize * 0.05d); 1033 return (currentPosExamples.size() <= maxPosRemaining); 1034 } 1035 } 1036 1037 private boolean partialSolutionTerminationCriteriaSatisfied(){ 1038 return stop || todoList.isEmpty() || currentPosExampleTrees.isEmpty() || (useDisjunction && isPartialSolutionTimeExpired()) || isTimeExpired(); 1039 } 1040 1041 private boolean isPartialSolutionTimeExpired(){ 1042 return maxTreeComputationTimeInSeconds > 0 && getRemainingPartialSolutionTime() > 0; 1043 } 1044 1045 private long getRemainingPartialSolutionTime() { 1046 return (long) (maxTreeComputationTimeInSeconds - (System.currentTimeMillis() - partialSolutionStartTime) / 1000); 1047 } 1048 1049 /** 1050 * Shows the current setup of the algorithm. 1051 */ 1052 private void printSetup(){ 1053 String setup = "Setup:"; 1054 setup += "\n#Pos. examples:" + currentPosExampleTrees.size(); 1055 setup += "\n#Neg. examples:" + currentNegExampleTrees.size(); 1056 setup += "\nHeuristic:" + heuristic.getHeuristicType().name(); 1057 setup += "\nNoise value=" + noise; 1058 setup += "\nbeta=" + beta; 1059 logger.info(setup); 1060 } 1061 1062 /** 1063 * @param noisePercentage the noisePercentage to set 1064 */ 1065 public void setNoisePercentage(double noisePercentage) { 1066 this.noisePercentage = noisePercentage; 1067 } 1068 1069 /** 1070 * @param noise the noise to set 1071 */ 1072 public void setNoise(double noise) { 1073 this.noise = noise; 1074 } 1075 1076 /** 1077 * Default value is 1. Lower values force importance of covering positive examples. 1078 * @param beta the beta to set 1079 */ 1080 public void setBeta(double beta) { 1081 this.beta = beta; 1082 } 1083 1084 /** 1085 * Set the max. execution time for the computation of a partial solution. If this value isn't set, the 1086 * max. algorithm runtime will be used, thus, in worst case only one partial solution was computed. 1087 * 1088 * @param maxTreeComputationTimeInSeconds the max. computation for a partial solution tree 1089 */ 1090 public void setMaxTreeComputationTimeInSeconds(double maxTreeComputationTimeInSeconds) { 1091 this.maxTreeComputationTimeInSeconds = maxTreeComputationTimeInSeconds; 1092 } 1093 1094 /** 1095 * @return the heuristic 1096 */ 1097 public QueryTreeHeuristic getHeuristic() { 1098 return heuristic; 1099 } 1100 1101 /** 1102 * @param heuristic the heuristic to set 1103 */ 1104 public void setHeuristic(QueryTreeHeuristic heuristic) { 1105 this.heuristic = heuristic; 1106 } 1107 1108 /** 1109 * @param treeFactory the treeFactory to set 1110 */ 1111 public void setTreeFactory(org.dllearner.algorithms.qtl.impl.QueryTreeFactory treeFactory) { 1112 this.treeFactory = treeFactory; 1113 } 1114 1115 public EvaluatedRDFResourceTree getBestSolution(){ 1116 return currentPartialSolutions.last(); 1117 } 1118 1119 public SortedSet<EvaluatedRDFResourceTree> getSolutions(){ 1120 return currentPartialSolutions; 1121 } 1122 1123 public List<EvaluatedRDFResourceTree> getSolutionsAsList(){ 1124 // Collections.sort(list, Collections.reverseOrder()); 1125 return new ArrayList<>(currentPartialSolutions); 1126 } 1127 1128 /** 1129 * @param positiveExampleTrees the positive example trees to set 1130 */ 1131 public void setPositiveExampleTrees(Map<OWLIndividual,RDFResourceTree> positiveExampleTrees) { 1132 this.currentPosExampleTrees = new ArrayList<>(positiveExampleTrees.values()); 1133 this.currentPosExamples = new HashSet<>(positiveExampleTrees.keySet()); 1134 1135 for (Entry<OWLIndividual, RDFResourceTree> entry : positiveExampleTrees.entrySet()) { 1136 OWLIndividual ind = entry.getKey(); 1137 RDFResourceTree tree = entry.getValue(); 1138 tree2Individual.put(tree, ind); 1139 } 1140 } 1141 1142 /** 1143 * @param negativeExampleTrees the negative example trees to set 1144 */ 1145 public void setNegativeExampleTrees(Map<OWLIndividual,RDFResourceTree> negativeExampleTrees) { 1146 this.currentNegExampleTrees = new ArrayList<>(negativeExampleTrees.values()); 1147 this.currentNegExamples = new HashSet<>(negativeExampleTrees.keySet()); 1148 1149 for (Entry<OWLIndividual, RDFResourceTree> entry : negativeExampleTrees.entrySet()) { 1150 OWLIndividual ind = entry.getKey(); 1151 RDFResourceTree tree = entry.getValue(); 1152 tree2Individual.put(tree, ind); 1153 } 1154 } 1155 1156 /** 1157 * @param ks the ks to set 1158 */ 1159 @Autowired 1160 public void setKs(SparqlEndpointKS ks) { 1161 this.ks = ks; 1162 } 1163 1164 /** 1165 * @param maxTreeDepth the maximum depth of the trees, if those have to be generated 1166 * first. The default depth is 2. 1167 */ 1168 public void setMaxTreeDepth(int maxTreeDepth) { 1169 this.maxTreeDepth = maxTreeDepth; 1170 } 1171 1172 /** 1173 * @return the runtime in ms until the best solution was found 1174 */ 1175 public long getTimeBestSolutionFound() { 1176 return timeBestSolutionFound; 1177 } 1178 1179 /* (non-Javadoc) 1180 * @see java.lang.Object#clone() 1181 */ 1182 @Override 1183 public Object clone() throws CloneNotSupportedException { 1184 super.clone(); 1185 return new QTL2Disjunctive(this); 1186 } 1187}