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; 020 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.dllearner.core.AbstractCELA; 028import org.dllearner.core.AbstractClassExpressionLearningProblem; 029import org.dllearner.core.AbstractReasonerComponent; 030import org.dllearner.core.ComponentAnn; 031import org.dllearner.core.ComponentInitException; 032import org.dllearner.core.EvaluatedDescription; 033import org.dllearner.core.config.ConfigOption; 034import org.dllearner.core.owl.OWLObjectIntersectionOfImplExt; 035import org.dllearner.learningproblems.EvaluatedDescriptionPosNeg; 036import org.dllearner.learningproblems.ScorePosNeg; 037import org.semanticweb.owlapi.model.OWLClassExpression; 038import org.semanticweb.owlapi.model.OWLObjectProperty; 039 040/** 041 * Simple example learning algorithm exhaustively creating complex class 042 * expressions of the AL description logic. 043 */ 044@ComponentAnn(name = "Naive AL Learner", shortName = "naiveALLearner", version = 0.1) 045public class NaiveALLearner extends AbstractCELA{ 046 047 private Map<Integer, List<OWLClassExpression>> generatedDescriptions; 048 049 private boolean running = false; 050 @ConfigOption(defaultValue = "4", description = "maximum length of class expression") 051 private int maxLength = 4; 052 053 private OWLClassExpression bestDescription; 054 private ScorePosNeg bestScore; 055 056 public NaiveALLearner() { 057 } 058 059 public NaiveALLearner(AbstractClassExpressionLearningProblem lp, AbstractReasonerComponent reasoner) { 060 super(lp, reasoner); 061 } 062 @Override 063 public void start() { 064 running = true; 065 066 // first generate all possible complex class expressions up to a length 067 // of maxLength 068 for (int i=1; i<=maxLength; i++) { 069 generateDescriptions(i); 070 } 071 072 // now evaluate these expressions to find a description that best 073 // describes and distinguishes positive and negative examples 074 evaluateGeneratedDefinition(); 075 076 System.out.println("Best description: " + bestDescription); 077 System.out.println("Best score: " + bestScore); 078 stop(); 079 } 080 081 @Override 082 public void init() throws ComponentInitException { 083 generatedDescriptions = new HashMap<>(); 084 085 // start with owl:Thing 086 bestDescription = OWL_THING; 087 bestScore = null; 088 089 initialized = true; 090 } 091 092 @Override 093 public void stop() { 094 running = false; 095 } 096 097 @Override 098 public boolean isRunning() { 099 return running; 100 } 101 102 @Override 103 public OWLClassExpression getCurrentlyBestDescription() { 104 return bestDescription; 105 } 106 107 @Override 108 public EvaluatedDescription getCurrentlyBestEvaluatedDescription() { 109 return new EvaluatedDescriptionPosNeg(bestDescription,bestScore); 110 } 111 112 /** 113 * Generates new descriptions (i.e. concepts) of the length `length`. 114 * - `length` == 1: 115 * - all atomic classes are added to the set `generatedDescriptions` 116 * - the concepts owl:Thing and owl:Nothing are added 117 * - `length` == 2: 118 * - negations of all atomic classes are added 119 * - `length` == 3: 120 * - all atomic roles are added as limited existential quantification/ 121 * value restriction 122 * - all combinations of intersections of atomic classes are added 123 * - `length` > 3: 124 * - all concepts of length `length`-1 are extended by intersection 125 * with an atomic class 126 * - all concepts of length `length`-2 are extended by limited 127 * existential quantification/value restriction 128 * 129 * @param length the length 130 */ 131 private void generateDescriptions(int length) { 132 generatedDescriptions.put(length, new ArrayList<>()); 133 List<OWLClassExpression> thisLenDescriptions = generatedDescriptions.get(length); 134 135 if (length == 1) { 136 // add atomic classes 137 thisLenDescriptions.add(OWL_THING); 138 thisLenDescriptions.add(OWL_NOTHING); 139 140 for (OWLClassExpression atomicClass : reasoner.getAtomicConceptsList()) { 141 thisLenDescriptions.add(atomicClass); 142 } 143 } 144 145 if (length == 2) { 146 // add negation of atomic classes 147 for (OWLClassExpression atomicClass : reasoner.getAtomicConceptsList()) { 148 thisLenDescriptions.add(dataFactory.getOWLObjectComplementOf(atomicClass)); 149 } 150 } 151 152 if (length == 3) { 153 // add limited existential quantification/value restriction 154 for (OWLObjectProperty prop : reasoner.getObjectProperties()) { 155 thisLenDescriptions.add(dataFactory.getOWLObjectSomeValuesFrom(prop, OWL_THING)); 156 thisLenDescriptions.add(dataFactory.getOWLObjectAllValuesFrom(prop, OWL_THING)); 157 158 for (OWLClassExpression atomicClass : reasoner.getAtomicConceptsList()) { 159 thisLenDescriptions.add(dataFactory.getOWLObjectAllValuesFrom(prop, atomicClass)); 160 } 161 } 162 163 // add intersections of atomic concepts 164 for (OWLClassExpression leftAtomicConcept : reasoner.getAtomicConceptsList()) { 165 for(OWLClassExpression rightAtomicConcept : reasoner.getAtomicConceptsList()) { 166 thisLenDescriptions.add(new OWLObjectIntersectionOfImplExt( 167 Arrays.asList(leftAtomicConcept, rightAtomicConcept))); 168 } 169 } 170 } 171 172 if (length > 3) { 173 // add ALL <objectProperty>.<generatedConcept> for all concepts of length 174 // `length`-2 175 for (OWLObjectProperty objProp : reasoner.getObjectProperties()) { 176 for (OWLClassExpression description : generatedDescriptions.get(length-2)) { 177 thisLenDescriptions.add(dataFactory.getOWLObjectAllValuesFrom(objProp, description)); 178 } 179 } 180 // add <generatedConcept> INTERSECT <atomicClass> for all concepts 181 // of length `length`-1 182 for (OWLClassExpression atomicConcept : reasoner.getAtomicConceptsList()) { 183 for (OWLClassExpression concept : generatedDescriptions.get(length-1)) { 184 thisLenDescriptions.add(new OWLObjectIntersectionOfImplExt( 185 Arrays.asList(concept, atomicConcept))); 186 } 187 } 188 } 189 } 190 191 public void setMaxLength(int length) { 192 maxLength = length; 193 } 194 195 public int getMaxLength() { 196 return maxLength; 197 } 198 199 private void evaluateGeneratedDefinition() { 200 double bestScoreVal = Double.NEGATIVE_INFINITY; 201 double tmpScoreVal; 202 ScorePosNeg tmpScore; 203 for (int i=1; i<=maxLength; i++) { 204 for (OWLClassExpression description : generatedDescriptions.get(i)) { 205 tmpScore = (ScorePosNeg) learningProblem.computeScore(description); 206 tmpScoreVal = tmpScore.getScoreValue(); 207 if (tmpScoreVal > bestScoreVal) { 208 bestDescription = description; 209 bestScore = tmpScore; 210 bestScoreVal = tmpScoreVal; 211 } 212 } 213 } 214 } 215}