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}