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.learningproblems;
020
021import com.google.common.collect.Sets;
022import org.apache.commons.lang3.NotImplementedException;
023import org.dllearner.core.AbstractReasonerComponent;
024import org.dllearner.core.ComponentAnn;
025import org.dllearner.core.ComponentInitException;
026import org.dllearner.core.EvaluatedDescription;
027import org.dllearner.core.config.ConfigOption;
028import org.dllearner.utilities.owl.OWLClassExpressionUtils;
029import org.semanticweb.owlapi.model.OWLClassExpression;
030import org.semanticweb.owlapi.model.OWLIndividual;
031import org.semanticweb.owlapi.model.OWLNamedIndividual;
032
033import java.util.Set;
034import java.util.SortedSet;
035import java.util.TreeSet;
036
037/**
038 * @author Jens Lehmann
039 *
040 */
041@ComponentAnn(name = "PosNegLPStrict", shortName = "posNegStrict", version = 0.1, description = "three valued definition learning problem")
042public class PosNegLPStrict extends PosNegLP {
043
044        private Set<OWLIndividual> neutralExamples;
045
046        @ConfigOption(description = "if set to true neutral examples are penalised")
047        private boolean penaliseNeutralExamples = false;
048        
049        private static final double defaultAccuracyPenalty = 1;
050
051        @ConfigOption(description = "penalty for pos/neg examples which are classified as neutral", defaultValue = "1.0")
052        private double accuracyPenalty = defaultAccuracyPenalty;
053
054        private static final double defaultErrorPenalty = 3;
055        @ConfigOption(description = "penalty for pos. examples classified as negative or vice versa", defaultValue = "3.0")
056        private double errorPenalty = defaultErrorPenalty;
057        
058
059        public void setAccuracyPenalty(double accuracyPenalty) {
060                this.accuracyPenalty = accuracyPenalty;
061        }
062
063        public void setErrorPenalty(double errorPenalty) {
064                this.errorPenalty = errorPenalty;
065        }
066
067        public void setPenaliseNeutralExamples(boolean penaliseNeutralExamples) {
068                this.penaliseNeutralExamples = penaliseNeutralExamples;
069        }
070
071        public PosNegLPStrict(AbstractReasonerComponent reasoningService) {
072                super(reasoningService);
073        }
074
075        public PosNegLPStrict() { super(); }
076
077        /* (non-Javadoc)
078         * @see org.dllearner.core.Component#init()
079         */
080        @Override
081        public void init() throws ComponentInitException {
082                super.init();
083                // compute neutral examples, i.e. those which are neither positive
084                // nor negative (we have to take care to copy sets instead of 
085                // modifying them)
086                neutralExamples = Sets.intersection(getReasoner().getIndividuals(), positiveExamples);
087                neutralExamples.retainAll(negativeExamples);
088                
089                initialized = true;
090        }
091
092        /* (non-Javadoc)
093         * @see org.dllearner.learningproblems.DefinitionLP#computeScore(org.dllearner.core.dl.Concept)
094         */
095        @Override
096        public ScorePosNeg computeScore(OWLClassExpression concept) {
097                if(isUseRetrievalForClassification()) {
098                        SortedSet<OWLIndividual> posClassified = getReasoner().getIndividuals(concept);
099                        SortedSet<OWLIndividual> negClassified = getReasoner().getIndividuals(dataFactory.getOWLObjectComplementOf(concept));
100                        Set<OWLIndividual> neutClassified = new TreeSet<>(Sets.intersection(getReasoner().getIndividuals(),posClassified));
101                        neutClassified.retainAll(negClassified);
102                        return new ScoreThreeValued(
103                                        OWLClassExpressionUtils.getLength(concept), accuracyPenalty, errorPenalty,
104                                        penaliseNeutralExamples, getPercentPerLengthUnit(), posClassified, neutClassified,
105                                        negClassified, positiveExamples, neutralExamples, negativeExamples);
106        } else {
107                if(getReasoner().getReasonerType().isOWLAPIReasoner()) {
108                        if(penaliseNeutralExamples)
109                                throw new Error("It does not make sense to use single instance checks when" +
110                                                "neutral examples are penalized. Use Retrievals instead.");
111                                
112                        // TODO: umschreiben in instance checks
113                        SortedSet<OWLIndividual> posClassified = new TreeSet<>();
114                        SortedSet<OWLIndividual> negClassified = new TreeSet<>();
115                        // Beispiele durchgehen
116                        // TODO: Implementierung ist ineffizient, da man hier schon in Klassen wie
117                        // posAsNeut, posAsNeg etc. einteilen koennte; so wird das extra in der Score-Klasse
118                        // gemacht; bei wichtigen Benchmarks des 3-wertigen Lernproblems muesste man das
119                        // umstellen
120                        // pos => pos
121                        for(OWLIndividual example : positiveExamples) {
122                                if(getReasoner().hasType(concept, example))
123                                        posClassified.add(example);
124                        }
125                        // neg => pos
126                        for(OWLIndividual example: negativeExamples) {
127                                if(getReasoner().hasType(concept, example))
128                                        posClassified.add(example);
129                        }
130
131                                OWLClassExpression negatedConcept = dataFactory.getOWLObjectComplementOf(concept);
132
133                        // pos => neg
134                        for(OWLIndividual example : positiveExamples) {
135                                if(getReasoner().hasType(negatedConcept, example))
136                                        negClassified.add(example);
137                        }
138                        // neg => neg
139                        for(OWLIndividual example : negativeExamples) {
140                                if(getReasoner().hasType(negatedConcept, example))
141                                        negClassified.add(example);
142                        }                       
143                        
144                        Set<OWLIndividual> neutClassified = new TreeSet<>(Sets.intersection(getReasoner().getIndividuals(),posClassified));
145                        neutClassified.retainAll(negClassified);
146                                return new ScoreThreeValued(OWLClassExpressionUtils.getLength(concept), accuracyPenalty, errorPenalty,
147                                                                                        penaliseNeutralExamples, getPercentPerLengthUnit(), posClassified,
148                                                                                        neutClassified, negClassified, positiveExamples, neutralExamples,
149                                                                                        negativeExamples);
150                        } else
151                        throw new Error("score cannot be computed in this configuration");
152        }
153        }
154
155        @Override
156        public ScorePosNeg<OWLNamedIndividual> computeScore(OWLClassExpression ce, double noise) {
157                return null;
158        }
159
160        public Set<OWLIndividual> getNeutralExamples() {
161                return neutralExamples;
162        }
163
164        /**
165         * @return the accuracyPenalty
166         */
167        public double getAccuracyPenalty() {
168                return accuracyPenalty;
169        }
170
171        /**
172         * @return the errorPenalty
173         */
174        public double getErrorPenalty() {
175                return errorPenalty;
176        }
177
178        /**
179         * @return the penaliseNeutralExamples
180         */
181        public boolean isPenaliseNeutralExamples() {
182                return penaliseNeutralExamples;
183        }
184
185        /* (non-Javadoc)
186         * @see org.dllearner.core.LearningProblem#getAccuracyOrTooWeak(org.dllearner.core.owl.Description, double)
187         */
188        @Override
189        public double getAccuracyOrTooWeak(OWLClassExpression description, double minAccuracy) {
190                throw new NotImplementedException("Not implemented yet!");
191        }
192
193        /* (non-Javadoc)
194         * @see org.dllearner.core.LearningProblem#evaluate(org.dllearner.core.owl.Description)
195         */
196        @Override
197        public EvaluatedDescription evaluate(OWLClassExpression description) {
198                throw new NotImplementedException("Not implemented yet!");
199        }
200}