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.hybridgp; 020 021import java.util.Random; 022import java.util.Set; 023import java.util.SortedMap; 024import java.util.TreeMap; 025 026import org.dllearner.algorithms.gp.Program; 027import org.dllearner.core.AbstractReasonerComponent; 028import org.dllearner.learningproblems.PosNegLP; 029import org.dllearner.learningproblems.ScorePosNeg; 030import org.dllearner.refinementoperators.PsiDown; 031import org.dllearner.refinementoperators.PsiUp; 032import org.dllearner.utilities.owl.ConceptTransformation; 033import org.dllearner.utilities.owl.OWLClassExpressionUtils; 034import org.semanticweb.owlapi.model.OWLClassExpression; 035 036public class Psi implements GeneticRefinementOperator { 037 038 PsiUp pu; 039 PsiDown pd; 040 PosNegLP learningProblem; 041 int nrOfPositiveExamples; 042 int nrOfNegativeExamples; 043 Random random; 044 045 // Cache, damit keine Konzepte doppelt ausgewertet werden 046 public SortedMap<OWLClassExpression,ScorePosNeg> evalCache = new TreeMap<>(); 047 048 // Cache, damit PsiDown bzw. PsiUp nicht mehrfach für gleiches Konzept 049 // aufgerufen werden 050 public SortedMap<OWLClassExpression,Set<OWLClassExpression>> pdCache = new TreeMap<>(); 051 public SortedMap<OWLClassExpression,Set<OWLClassExpression>> puCache = new TreeMap<>(); 052 053 // Statistiken 054 int conceptCacheHits = 0; 055 int nrOfRequests = 0; 056 int pdCacheHits = 0; 057 private long pdRequests = 0; 058 int puCacheHits = 0; 059 private long puRequests = 0; 060 private long psiApplicationStartTime = 0; 061 private long psiApplicationTimeNs = 0; 062 private long psiReasoningStartTime = 0; 063 private long psiReasoningTimeNs = 0; 064 065 @SuppressWarnings("unused") 066 private long someTimeStart = 0; 067 public long someTime = 0; 068 069 public Psi(PosNegLP learningProblem, AbstractReasonerComponent reasoningService) { //, PsiUp pu, PsiDown pd) { 070 // this.pu = pu; 071 // this.pd = pd; 072 this.learningProblem = learningProblem; 073 pu = new PsiUp(learningProblem, reasoningService); 074 pd = new PsiDown(learningProblem, reasoningService); 075 nrOfPositiveExamples = learningProblem.getPositiveExamples().size(); 076 nrOfNegativeExamples = learningProblem.getNegativeExamples().size(); 077 random = new Random(); 078 } 079 080 public OWLClassExpression applyPsi(OWLClassExpression concept, int coveredPositives, int coveredNegatives) { 081 // Wahrscheinlichkeit für upward refinement berechnen 082 double tmp = coveredNegatives/(double)nrOfNegativeExamples; 083 double tmp2 = coveredPositives/(double)nrOfPositiveExamples; 084 085 double downwardProbability = tmp/(1+tmp-tmp2); 086 087 boolean debug = false; 088 if(debug) { 089 System.out.println("negative percentage covered: " + tmp); 090 System.out.println("positive percentage covered: " + tmp2); 091 // System.out.println("upward probability: upward") 092 } 093 094 if(downwardProbability<0 || downwardProbability>1) { 095 096 // bei Division gibt es Ungenauigkeit, so dass man einen kleinen 097 // Toleranzbereich lassen muss 098 if(downwardProbability < -0.0001) 099 throw new RuntimeException(); 100 else if(downwardProbability > 1.0001) 101 throw new RuntimeException(); 102 // Rundung auf korrekten Wert 103 else if(downwardProbability<0) 104 downwardProbability = 0d; 105 else 106 downwardProbability = 1d; 107 } 108 109 // System.out.println(upwardProbability); 110 111 boolean downward = (Math.random()<=downwardProbability); 112 113 // someTimeStart = System.nanoTime(); 114 // downward oder upward refinement operator anwenden 115 Set<OWLClassExpression> refinements; 116 if(downward) { 117 pdRequests++; 118 // Cache aufrufen 119 refinements = pdCache.get(concept); 120 if(refinements == null) { 121 refinements = pd.refine(concept); 122 pdCache.put(concept, refinements); 123 } else 124 pdCacheHits++; 125 } else { 126 puRequests++; 127 refinements = puCache.get(concept); 128 if(refinements == null) { 129 refinements = pu.refine(concept); 130 puCache.put(concept, refinements); 131 } else 132 puCacheHits++; 133 } 134 135 /* 136 if(puRequests % 500 == 0 && !downward) { 137 System.out.println(concept); 138 for(Concept refinement : refinements) 139 System.out.println(" " + refinement); 140 }*/ 141 142 143 // someTime += System.nanoTime() - someTimeStart; 144 // System.out.println(refinements.size()); 145 146 String dir = ""; 147 int prob = -1; 148 if(debug) { 149 if(downward) { 150 dir = "downward"; 151 prob = (int) (100 * downwardProbability); 152 } else { 153 dir = "upward"; 154 prob = (int) (100 * (1-downwardProbability)); 155 } 156 } 157 158 159 // ein refinement zufällig auswählen 160 OWLClassExpression[] array = refinements.toArray(new OWLClassExpression[refinements.size()]); 161 // kein refinement gefunden 162 if(array.length==0) { 163 if(debug) { 164 System.out.println("message: no " + dir + " refinement found for " + concept); 165 System.out.println(); 166 } 167 // Konzept selbst wird zurückgegeben (also reproduction) 168 return concept; 169 } 170 171 int position = random.nextInt(array.length); 172 OWLClassExpression returnConcept = array[position]; 173 ConceptTransformation.cleanConcept(returnConcept); 174 175 // das Rückgabekonzept wird geklont, damit alle parent-Links repariert 176 // werden (damit andere GP-Operatoren korrekt funktionieren) 177 OWLClassExpression returnConceptClone = OWLClassExpressionUtils.clone(returnConcept); 178 179 if(debug) { 180 System.out.println(concept + " " + dir + "("+prob+"%) to " + returnConcept); 181 System.out.println(); 182 } 183 184 return returnConceptClone; 185 } 186 187 @Override 188 public Program applyOperator(Program program) { 189 psiApplicationStartTime = System.nanoTime(); 190 nrOfRequests++; 191 192 OWLClassExpression concept = program.getTree(); 193 // es muss sichergestellt sein, dass Konjunktionen nur als MultConjunctions 194 // vorhanden sind (analog bei Disjunktion) => effizienter wäre eine Auslagerung 195 // dieses Codes in die Konzepterzeugung, da die Transformation häufig nichts 196 // bringt; allerdings sollte GP noch kompatibel mit anderen Operatoren bleiben 197 // Concept conceptMod = ConceptTransformation.transformToMulti(concept); 198 // sicherstellen, dass Konstrukte wie NOT TOP, die momentan nicht vom 199 // Operator behandelt werden können, herausfallen (TODO: anschauen, ob es 200 // sich lohnt Operatoren zu definieren, die keine Negationsnormalform 201 // erfordern) 202 203 OWLClassExpression conceptMod = concept.getNNF(); 204 // um mehr Cache Hits zu bekommen, wird noch vereinfach und geordnet 205 206 207 OWLClassExpression conceptModForCache = ConceptTransformation.applyEquivalenceRules(conceptMod); 208 209 ScorePosNeg score = program.getScore(); 210 // Eval-Cache füllen 211 evalCache.put(conceptModForCache, score); 212 213 // System.out.println("covered positives: " + score.getCoveredPositives()); 214 // System.out.println("covered negatives: " + score.getCoveredNegatives()); 215 int coveredPositives = score.getCoveredPositives().size(); 216 int coveredNegatives = score.getCoveredNegatives().size(); 217 // someTimeStart = System.nanoTime(); 218 OWLClassExpression newConcept = applyPsi(conceptMod, coveredPositives, coveredNegatives); 219 ConceptTransformation.cleanConcept(newConcept); 220 // someTime += System.nanoTime() - someTimeStart; 221 // newConcept.setParent(null); 222 223 /////////// TESTCODE: umwandeln des erhaltenen Konzepts 224 // someTimeStart = System.nanoTime(); 225 OWLClassExpression newConceptMod = ConceptTransformation.applyEquivalenceRules(newConcept); 226 // someTime += System.nanoTime() - someTimeStart; 227 /////////// 228 229 // versuchen Reasoner-Cache zu treffen 230 // Problem: Score hängt von Konzeptlänge ab!! => muss hier explizit 231 // reingerechnet werden 232 ScorePosNeg newScore = evalCache.get(newConceptMod); 233 234 if(newScore==null) { 235 psiReasoningStartTime = System.nanoTime(); 236 newScore = (ScorePosNeg) learningProblem.computeScore(newConcept); 237 psiReasoningTimeNs += System.nanoTime() - psiReasoningStartTime; 238 239 evalCache.put(newConceptMod, newScore); 240 } else { 241 conceptCacheHits++; 242 243 // ToDo: es muss jetzt explizit ein neues Score-Objekt 244 // erzeugt werden, welches die geänderte Konzeptlänge 245 // berücksichtigt 246 newScore = newScore.getModifiedLengthScore(OWLClassExpressionUtils.getLength(newConcept)); 247 } 248 249 /* 250 if(nrOfRequests % 1000 == 0) { 251 System.out.println(concept); 252 System.out.println(newConcept); 253 } 254 */ 255 256 Program newProgram = new Program(newScore, newConcept); 257 psiApplicationTimeNs += System.nanoTime() - psiApplicationStartTime; 258 return newProgram; 259 } 260 261 // gibt die GröÃe des Caches zurück (gutes Maà um zu sehen, ob überhaupt 262 // neue Konzepte erforscht werden) 263 public int getCacheSize() { 264 return evalCache.size(); 265 } 266 267 public int getConceptCacheHits() { 268 return conceptCacheHits; 269 } 270 271 public int getNrOfRequests() { 272 return nrOfRequests; 273 } 274 275 public long getPsiApplicationTimeNs() { 276 return psiApplicationTimeNs; 277 } 278 279 public long getPsiReasoningTimeNs() { 280 return psiReasoningTimeNs; 281 } 282 283 public int getPdCacheHits() { 284 return pdCacheHits; 285 } 286 287 public int getPuCacheHits() { 288 return puCacheHits; 289 } 290 291 public long getPdRequests() { 292 return pdRequests; 293 } 294 295 public long getPuRequests() { 296 return puRequests; 297 } 298 299 public SortedMap<OWLClassExpression, Set<OWLClassExpression>> getPdCache() { 300 return pdCache; 301 } 302 303 public SortedMap<OWLClassExpression, Set<OWLClassExpression>> getPuCache() { 304 return puCache; 305 } 306 307}