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.ocel; 020 021import org.dllearner.core.AbstractCELA; 022import org.dllearner.core.AbstractSearchTreeNode; 023import org.dllearner.core.StringRenderer; 024import org.dllearner.learningproblems.PosNegLP; 025import org.dllearner.utilities.datastructures.SearchTreeNode; 026import org.dllearner.utilities.datastructures.WeakSearchTreeNode; 027import org.semanticweb.owlapi.model.OWLClassExpression; 028import org.semanticweb.owlapi.model.OWLIndividual; 029 030import java.text.DecimalFormat; 031import java.util.Set; 032import java.util.SortedSet; 033import java.util.TreeSet; 034 035/** 036 * 037 * Represents a node in the search tree. A node consists of 038 * the following parts: 039 * 040 * ... (see paper) ... 041 * 042 * @author Jens Lehmann 043 * 044 */ 045public class ExampleBasedNode extends AbstractSearchTreeNode<ExampleBasedNode> implements SearchTreeNode, WeakSearchTreeNode { 046 047 private static DecimalFormat df = new DecimalFormat(); 048 049 // example based variables 050 private Set<OWLIndividual> coveredPositives; 051 private Set<OWLIndividual> coveredNegatives; 052 053 // the method by which quality was evaluated in this node 054 public enum QualityEvaluationMethod { START, REASONER, TOO_WEAK_LIST, OVERLY_GENERAL_LIST } 055 056 private QualityEvaluationMethod qualityEvaluationMethod = QualityEvaluationMethod.START; 057 058 // all properties of a node in the search tree 059 private OWLClassExpression concept; 060 private int horizontalExpansion; 061 // specifies whether the node is too weak (exceeds the max. nr allowed 062 // misclassifications of positive examples) 063 private boolean isTooWeak; 064 private boolean isQualityEvaluated; 065 private boolean isRedundant; 066 067 // apart from the child nodes, we also keep child concepts 068 private SortedSet<OWLClassExpression> childConcepts = new TreeSet<>(); 069 070 // a flag whether this could be a solution for a posonly learning problem 071 private boolean isPosOnlyCandidate = true; 072 073 private OCEL learningAlgorithm; 074 075 public ExampleBasedNode(OWLClassExpression concept, AbstractCELA learningAlgorithm) { 076 this.concept = concept; 077 horizontalExpansion = 0; 078 isQualityEvaluated = false; 079 this.learningAlgorithm = (OCEL) learningAlgorithm; 080 } 081 082 public void setHorizontalExpansion(int horizontalExpansion) { 083 this.horizontalExpansion = horizontalExpansion; 084 } 085 086 public void setRedundant(boolean isRedundant) { 087 this.isRedundant = isRedundant; 088 } 089 090 public void setTooWeak(boolean isTooWeak) { 091 if(isQualityEvaluated) 092 throw new RuntimeException("Cannot set quality of a node more than once."); 093 this.isTooWeak = isTooWeak; 094 isQualityEvaluated = true; 095 } 096 097 @Override 098 public void addChild(ExampleBasedNode child) { 099 super.addChild(child); 100 childConcepts.add(child.concept); 101 } 102 103 public void setQualityEvaluationMethod(QualityEvaluationMethod qualityEvaluationMethod) { 104 this.qualityEvaluationMethod = qualityEvaluationMethod; 105 } 106 107 public void setCoveredExamples(Set<OWLIndividual> coveredPositives, Set<OWLIndividual> coveredNegatives) { 108 this.coveredPositives = coveredPositives; 109 this.coveredNegatives = coveredNegatives; 110 isQualityEvaluated = true; 111 } 112 113 public int getQuality() { 114 return getCovPosMinusCovNeg(); 115 } 116 117 @Override 118 public String toString() { 119 return getShortDescription(); 120 } 121 122 public String toSimpleString() { 123 String ret = concept.toString() + " [q:"; 124 if(isTooWeak) 125 ret += "tw"; 126 else 127 ret += coveredNegatives.size(); 128 ret += ", he:" + horizontalExpansion + ", children:" + children.size() + "]"; 129 return ret; 130 } 131 132 public String getShortDescription() { 133 return StringRenderer.getRenderer().render(concept) + getStats(); 134 } 135 136 public String getStats() { 137 String ret = " ["; 138 139 if(isTooWeak) 140 ret += "q:tw"; 141 else { 142 double accuracy = 100 * getAccuracy(); 143 ret += "acc:" + df.format(accuracy) + "% "; 144 145 // comment this out to display the heuristic score with default parameters 146 // learningAlgorithm.getHeuristic() 147 int nrOfPositiveExamples = ((PosNegLP) learningAlgorithm.getLearningProblem()).getPositiveExamples().size(); 148 int nrOfNegativeExamples = ((PosNegLP) learningAlgorithm.getLearningProblem()).getNegativeExamples().size(); 149 double heuristicScore = MultiHeuristic.getNodeScore(this, nrOfPositiveExamples, nrOfNegativeExamples, learningAlgorithm.getNegativeWeight(), learningAlgorithm.getStartNodeBonus(), learningAlgorithm.getExpansionPenaltyFactor(), learningAlgorithm.getNegationPenalty()); 150 ret += "h:" +df.format(heuristicScore) + " "; 151 152 int wrongPositives = nrOfPositiveExamples - coveredPositives.size(); 153 ret += "q:" + wrongPositives + "p-" + coveredNegatives.size() + "n"; 154 } 155 156 ret += " ("+qualityEvaluationMethod+"), he:" + horizontalExpansion; 157 ret += " c:" + children.size() + "]"; 158 159 return ret; 160 } 161 162 public double getAccuracy() { 163 int tp = coveredPositives.size(); 164 int fp = coveredNegatives.size(); 165 int tn = ((PosNegLP)learningAlgorithm.getLearningProblem()).getNegativeExamples().size() - fp; 166 int fn = ((PosNegLP)learningAlgorithm.getLearningProblem()).getPositiveExamples().size() - tp; 167 168 double accuracy = ((PosNegLP)learningAlgorithm.getLearningProblem()).getAccuracyMethod().getAccOrTooWeak2(tp, fn, fp, tn, 1); 169 if (accuracy == -1 && !isTooWeak) 170 throw new RuntimeException("Accuracy says weak but node is not marked as such."); 171 return accuracy; 172 } 173 174 /** 175 * Used to detect whether one node is more accurate than another one 176 * with calculating accuracy itself. 177 * @return Number of covered positives minus number of covered negatives. 178 */ 179 public int getCovPosMinusCovNeg() { 180 return coveredPositives.size() - coveredNegatives.size(); 181 } 182 183 public Set<OWLIndividual> getCoveredPositives() { 184 return coveredPositives; 185 } 186 187 public Set<OWLIndividual> getCoveredNegatives() { 188 return coveredNegatives; 189 } 190 191 public SortedSet<OWLClassExpression> getChildConcepts() { 192 return childConcepts; 193 } 194 195 public OWLClassExpression getConcept() { 196 return concept; 197 } 198 199 @Override 200 public OWLClassExpression getExpression() { 201 return getConcept(); 202 } 203 204 public QualityEvaluationMethod getQualityEvaluationMethod() { 205 return qualityEvaluationMethod; 206 } 207 208 public int getHorizontalExpansion() { 209 return horizontalExpansion; 210 } 211 public boolean isQualityEvaluated() { 212 return isQualityEvaluated; 213 } 214 public boolean isRedundant() { 215 return isRedundant; 216 } 217 @Override 218 public boolean isTooWeak() { 219 return isTooWeak; 220 } 221 222}