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.refinementoperators;
020
021import org.dllearner.core.ComponentAnn;
022import org.dllearner.core.ComponentInitException;
023import org.dllearner.core.config.ConfigOption;
024import org.dllearner.utilities.owl.OWLClassExpressionLengthMetric;
025import org.dllearner.utilities.owl.OWLClassExpressionUtils;
026import org.semanticweb.owlapi.model.OWLClassExpression;
027import uk.ac.manchester.cs.owl.owlapi.OWLObjectComplementOfImpl;
028
029import java.util.List;
030import java.util.Set;
031import java.util.TreeSet;
032
033/**
034 * The class uses an existing refinement operator and inverts it, i.e. a 
035 * downward refinement operator is turned into an upward refinement operator
036 * and vice versa.
037 * 
038 * @author Jens Lehmann
039 *
040 */
041@ComponentAnn(name = "OperatorInverter", shortName = "inv_op", version = 0.1)
042public class OperatorInverter extends AbstractRefinementOperator implements LengthLimitedRefinementOperator {
043
044        @ConfigOption(description = "class expression length calculation metric")
045        private OWLClassExpressionLengthMetric lengthMetric;
046
047        public LengthLimitedRefinementOperator getOperator() {
048                return operator;
049        }
050
051        public void setOperator(LengthLimitedRefinementOperator operator) {
052                this.operator = operator;
053                this.lengthMetric = operator.getLengthMetric();
054                if (this.lengthMetric == null) {
055                        this.lengthMetric  = OWLClassExpressionLengthMetric.getDefaultMetric();
056                }
057        }
058
059        public boolean isUseNegationNormalForm() {
060                return useNegationNormalForm;
061        }
062
063        public void setUseNegationNormalForm(boolean useNegationNormalForm) {
064                this.useNegationNormalForm = useNegationNormalForm;
065        }
066
067        public boolean isGuaranteeLength() {
068                return guaranteeLength;
069        }
070
071        public void setGuaranteeLength(boolean guaranteeLength) {
072                this.guaranteeLength = guaranteeLength;
073        }
074
075        @ConfigOption(description = "operator to invert", required = true)
076        private LengthLimitedRefinementOperator operator;
077        @ConfigOption(description = "whether to apply NNF", defaultValue = "true")
078        private boolean useNegationNormalForm = true;
079        @ConfigOption(description = "Whether inverse solutions must respect the desired max length", defaultValue = "true")
080        private boolean guaranteeLength = true;
081        
082        public OperatorInverter(LengthLimitedRefinementOperator operator) {
083                this.operator = operator;
084                this.lengthMetric = operator.getLengthMetric();
085        }
086
087        public OperatorInverter() {
088        }
089        
090        @Override
091        public Set<OWLClassExpression> refine(OWLClassExpression description) {
092                Set<OWLClassExpression> refinements = operator.refine(getNegation(description));
093                TreeSet<OWLClassExpression> results = new TreeSet<>();
094                for(OWLClassExpression d : refinements) {
095                        results.add(getNegation(d));
096                }
097                return results;
098        }
099
100        @Override
101        public Set<OWLClassExpression> refine(OWLClassExpression description, int maxLength) {
102                OWLClassExpression negatedDescription = getNegation(description);
103//              System.out.println("negated description: " + negatedDescription);
104                // concept length can change because of the conversion process; as a heuristic
105                // we increase maxLength by the length difference of negated and original concept
106                int lengthDiff = Math.max(0, OWLClassExpressionUtils.getLength(negatedDescription, lengthMetric) - OWLClassExpressionUtils.getLength(description, lengthMetric));
107                Set<OWLClassExpression> refinements = operator.refine(negatedDescription, maxLength+lengthDiff+1);
108//              System.out.println("refinv: " + refinements);
109                TreeSet<OWLClassExpression> results = new TreeSet<>();
110                for(OWLClassExpression d : refinements) {
111                        OWLClassExpression dNeg = getNegation(d);
112//                      System.out.println("dNeg: " + dNeg);
113                        // to satisfy the guarantee that the method does not return longer
114                        // concepts, we perform an additional check
115                        if(!guaranteeLength || OWLClassExpressionUtils.getLength(dNeg, lengthMetric) <= maxLength) {
116                                results.add(dNeg);
117                        }
118                }
119                return results; 
120        }
121
122        @Override
123        public Set<OWLClassExpression> refine(OWLClassExpression description, int maxLength,
124                        List<OWLClassExpression> knownRefinements) {
125                throw new Error("Method not implemented.");
126        }
127
128        @Override
129        public void setLengthMetric(OWLClassExpressionLengthMetric lengthMetric) {
130                this.lengthMetric = lengthMetric;
131                operator.setLengthMetric(lengthMetric);
132        }
133
134        @Override
135        public OWLClassExpressionLengthMetric getLengthMetric() {
136                return this.lengthMetric;
137        }
138
139        private OWLClassExpression getNegation(OWLClassExpression description) {
140                OWLClassExpression negatedDescription = new OWLObjectComplementOfImpl(description);
141                if(useNegationNormalForm) {
142                        negatedDescription = negatedDescription.getNNF();
143                }
144                return negatedDescription;
145        }
146
147        @Override
148        public void init() throws ComponentInitException {
149                initialized = true;
150        }
151        
152}