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.decisiontrees.dsttdt.dst;
020
021import java.util.List;
022
023import org.dllearner.algorithms.decisiontrees.dsttdt.dst.MassFunction;
024import org.dllearner.algorithms.decisiontrees.utils.*;
025
026/**
027 * A class for representing a BBA
028 * @author Giuseppe Rizzo
029 *
030 * @param <T>
031 */
032public class MassFunction <T extends Comparable<? super T>> {
033        private  List<T> frameOfDiscernement;//frame of Discernement
034        private  List<List<T>> powerSet;
035        private double[] values;
036        
037        
038//      public static void setFrameOfDiscernement(){
039//              
040//      }
041//      
042        /**
043         * Constructor
044         * @param set
045         */
046        public MassFunction(List<T> set){
047                frameOfDiscernement=set;
048                generatePowerSet();
049                values= new double[powerSet.size()];
050                
051        }
052        /**
053         * method for generating the powerset of a frame Of Discernment
054         * @return
055         */
056        public void  generatePowerSet(){
057
058                powerSet=Combination.findCombinations(frameOfDiscernement);
059        }
060        
061        
062        /**
063         * Returns the subset of a frame of discernment
064         * @return insieme potenza
065         */
066        @SuppressWarnings({ "unchecked", "rawtypes", "unused" })
067        public  List<T>[] getSubsetsOfFrame(){
068                List[] result= new List[powerSet.size()];
069                int i=0;
070                for(List<T> elem:powerSet){
071                        
072                        result[i]=powerSet.get(i);
073                        i++;
074                }
075                return result;
076        }
077        
078        public List<T> getFrame(){
079                return frameOfDiscernement;
080                
081        }
082        /**
083         * Set a specific value for this BBA
084         */
085        public void setValues(List<T> label,double value){
086                int pos= SetUtils.find(label,powerSet);
087                values[pos]=value;
088                
089                
090        }
091        
092        
093        /**
094         * Returns the value of a BBA for a specific element of class 
095         * @param label
096         * @return the value of a bba or NaN 
097         */
098        public double getValue(List<T> label){
099                //System.out.println(valori.get(categoria));
100                int pos= SetUtils.find(label, powerSet);
101                return values[pos];
102        
103        }
104        
105        
106        public double getNonSpecificityMeasureValue(){
107                double result=0;
108                for(List<T> label: powerSet){
109                        if(!label.isEmpty())
110                                result+=(values[SetUtils.find(label, powerSet)]*Math.log(label.size())); 
111                }
112//              System.out.println("Non-sp: "+result);
113                return result;
114        }
115        
116        
117        public double getRandomnessMeasure(){
118                double result=0.0;
119                for (List<T> c: powerSet){
120                        double pignisticValue=getPignisticTransformation(c);
121                        int posCategoria = SetUtils.find(c, powerSet);
122                         result+= -1* (values[posCategoria]*Math.log(pignisticValue));
123                
124                }
125                return result;
126                
127                
128                        
129        }
130        
131        public double getPignisticTransformation(List<T> cl){
132                // it works certainly for {-1,+1} as a frame of discernement
133                 double result=0.0;
134                for(T element: cl){
135                        double pignisticValueForElement=0; // initialization
136                        for(List<T> categoria: powerSet){
137
138                                if(!categoria.isEmpty()){
139                                        if (categoria.contains(element)){
140                                                int posCategoria = SetUtils.find(categoria, powerSet);
141                                                pignisticValueForElement += values[posCategoria]/categoria.size();
142                                        }
143                                }
144
145                        }
146                        result+=pignisticValueForElement;
147                        
148                }
149                return result;
150        }
151        
152        
153        public double getGlobalUncertaintyMeasure(){
154                
155                double nonSpecificity= this.getNonSpecificityMeasureValue();
156                double randomness= this.getRandomnessMeasure();
157                final double LAMBDA= 0.1;
158                double result= ((1-LAMBDA)*nonSpecificity)+(LAMBDA*randomness);
159                return result;
160                
161        }
162        
163        /**
164         * The method computes a confusion measure described in Smarandache et.al as discordant measure
165         * @return
166         */
167        public double getConfusionMeasure(){
168                double result=0;
169                for(List<T> labels: powerSet){
170                        if(!labels.isEmpty())
171                                result-=(values[SetUtils.find(labels, powerSet)]*Math.log(this.computeBeliefFunction(labels))); 
172                }
173//              System.out.println("Non-sp: "+result);
174                return result;
175        }
176        
177        
178        @SuppressWarnings({ "unchecked", "rawtypes" })
179        /**
180         * combine two BBAs according to the Dempster rule
181         * @param function
182         * @return 
183         */
184        public MassFunction combineEvidences(MassFunction function){
185                MassFunction result= new MassFunction(frameOfDiscernement);
186                double conflitto=getConflict(function);
187                
188                for(List<T> elem:powerSet){
189                        int pos=SetUtils.find(elem, powerSet);
190                        
191                        for(List<T>hypothesis1: powerSet){
192                                for(List<T>hypothesis2:powerSet){
193                                        List<T> hypothesis12=SetUtils.intersection(hypothesis1, hypothesis2);
194                                                
195                                                if(!(hypothesis12.isEmpty())&&(SetUtils.areEquals(hypothesis12, elem))){
196                                                        SetUtils.find(hypothesis1, powerSet);
197                                                        SetUtils.find(hypothesis2, powerSet);
198                                                        double massProduct=getValue(hypothesis1)*function.getValue(hypothesis2)/conflitto;      
199                                                        result.values[pos]+=massProduct;
200                                                        
201                                                }
202//                                              System.out.println("Valori"+pos+"----"+result.valori[pos]);
203                                        }
204                                        
205                                }
206                                
207                                
208                        }
209                        
210                return result;
211                        
212                }
213                
214                
215                
216        
217        
218        
219        
220        /**
221         * Dempster rule for more BBAs
222         * @param function
223         * @return
224         */
225        @SuppressWarnings("rawtypes")
226        public MassFunction combineEvidences(MassFunction... function){
227                if(function.length==0)
228                        throw new RuntimeException("At least a mass function is required");
229                MassFunction result=this.combineEvidences(function[0]);
230                // associative operation
231                for(int i=1;i<function.length;i++){
232                        
233                        
234                        result= result.combineEvidences(function[i]);
235                        
236                }
237                
238                
239        
240                
241                return result;
242                
243        }
244        
245        /**
246         * Implementation of Dubois-Prade combination rule 
247         * @param function
248         * @return
249         */
250        @SuppressWarnings({ "unchecked", "rawtypes" })
251        public MassFunction<T> combineEvidencesDuboisPrade (MassFunction function){
252                
253                MassFunction<T> result= new MassFunction(frameOfDiscernement);
254                
255                // i-th hypothesis
256                for(List<T> elem:powerSet){
257                        int pos=SetUtils.find(elem, powerSet);
258                        // intersection betwee
259                        for(List<T>hypothesis1: powerSet){
260                                for(List<T>hypothesis2:powerSet){
261                                        List<T> hypothesis12=SetUtils.union(hypothesis1, hypothesis2);
262                                                // 
263                                                if((SetUtils.areEquals(hypothesis2, elem))){
264                                                        SetUtils.find(hypothesis1, powerSet);
265                                                        SetUtils.find(hypothesis2, powerSet);
266                                                        double massProduct=getValue(hypothesis1)*function.getValue(hypothesis2);        
267                                                        result.values[pos]+=massProduct;
268                                                        
269                                                }
270                                                
271                                        }
272                                        
273                                }
274//                              result.valori[pos]=result.valori[pos];
275                                
276                        }
277                        
278                return result;
279                
280        }
281        
282        @SuppressWarnings("rawtypes")
283        public MassFunction combineEvidencesDuboisPrade(MassFunction... function){
284                if(function.length==0)
285                        throw new RuntimeException("More than 1 mass function are required");
286                MassFunction result=this.combineEvidencesDuboisPrade(function[0]);
287                // operative association
288                for(int i=1;i<function.length;i++)
289                        result= result.combineEvidencesDuboisPrade(function[i]);
290                        
291                
292                
293                
294        
295                
296                return result;
297                
298        }
299        
300        
301        
302        /**
303         * Compute the conflict between two hypotheses
304         * @param function
305         * @return
306         */
307        @SuppressWarnings({ "rawtypes", "unchecked" })
308        public double getConflict(MassFunction function){
309                double emptyMass=0;
310                for(List<T> hypothesis:powerSet){
311//                      System.out.println("***************");
312//                      System.out.println("Ipotesi 1:"+ipotesi1);
313                        for(List<T> hypothesis2:powerSet){
314//                              System.out.println("Ipotesi 2:"+ipotesi2);
315                                List<T>intersezione=SetUtils.intersection(hypothesis,hypothesis2);
316                                if(!intersezione.isEmpty()){
317//                                      System.out.println("Intersezione vuota");
318                                        emptyMass+= (getValue(hypothesis)*function.getValue(hypothesis2));
319//                                      System.out.println(massaVuota);
320                                }
321                                
322                                
323                        }
324                        
325                        
326                }
327        
328                return (emptyMass);
329        }
330        /**
331         * Compute the belief function value
332         * @param hypothesis
333         * @return
334         */
335        public double computeBeliefFunction(List<T> hypothesis){
336                double bel_hypothesis=0;
337                for(List<T> elem:powerSet){
338                        // for all non-empty subsets
339                        if(!elem.isEmpty()&& hypothesis.containsAll(elem)){
340                                // somma le masse
341//                              System.out.println("m("+elem+")="+bel_ipotesi);
342                                bel_hypothesis+=getValue(elem);
343                                
344                        }
345                }
346//                      System.out.println("Belief:"+bel_ipotesi);
347                
348                return bel_hypothesis;
349        }
350        /**
351         * Compute the plausibility function value
352         * @param ipotesi
353         * @return
354         */
355        public double calcolaPlausibilityFunction(List<T> ipotesi){
356                // 
357                double pl_ipotesi=0;
358                for(List<T> elem:powerSet){
359                        
360                        if(!(SetUtils.intersection(ipotesi,elem)).isEmpty())
361                        
362                                pl_ipotesi+=getValue(elem);
363//                      System.out.println(pl_ipotesi);
364                }
365                        
366//              System.out.println("Plausibility"+pl_ipotesi);
367                return pl_ipotesi;
368                
369                
370        }
371        /**
372         * Computation of the confirmation function
373         * @param ipotesi
374         * @return
375         */
376        public double getConfirmationFunctionValue(List<T>ipotesi){
377                return (computeBeliefFunction(ipotesi)+calcolaPlausibilityFunction(ipotesi)-1);
378                
379        }
380        
381        public String toString(){
382                String res="";
383                for(int i=0;i<powerSet.size();i++){
384                        String string = ""+powerSet.get(i)+values[i];
385                        res+= string;
386                }
387                return res;
388        }
389
390        
391        
392        
393        
394        
395}
396