// --------------------------------------------------------------------------------- // Choquet integral of a function with respect to a measure // --------------------------------------------------------------------------------- // Downloadable: http://www.mdai.cat/ifao/ // References on aggregation functions and Choquet integral (examples from (Torra, Narukawa, 2007)) // V. Torra, Y. Narukawa (2007) Modeling Decisions, Springer. // V. Torra, Y. Narukawa, M. Sugeno (2014) Non-Additive Measures: Theory and Applications, Springer. // // Main functions: choquetIntegral, choquetIntegralWithFunction // // --------------------------------------------------------------------------------- // Fuzzy Measures / non-additive measures / capacities // Representation: an array of doubles for sets {000,001,010,011,...,111} // --------------------------------------------------------------------------------- // Examples of fuzzy measures: // Grabisch measure: {M,P,L} (Example 5.12 in (Torra & Narukawa,2007)) // -,L, P, PL, M, ML, MP, MPL val fmG = Array(0,0.3,0.45,0.9,0.45,0.9,0.5,1) // Grabisch/Sugeno lambda measure: {M,P,L} (Example 5.27 in (Torra & Narukawa,2007)) val fmL = Array(0,0.1842,0.2237,0.5061911,0.2237,0.5061911,0.5667687,1) // \mu_{p,w} -- 5 elements (Example 5.66, Table 5.9 in (Torra & Narukawa,2007)) val fmT = Array(0.0,0.04296875,0.1375,0.2375,0.06909722,0.1375, 0.3,0.5, 0.18333333,0.3,0.61666666,0.7625,0.38333333,0.61666666,0.81666666,0.9, 0.1,0.18333333,0.38333333,0.61666666,0.2375,0.38333333,0.70000000,0.81666666, 0.5,0.7,0.8625,0.93090277,0.7625,0.8625,0.95703125,1.0) // \mu_{WM} -- 4 elements (Table 6.4 in (Torra & Narukawa,2007)) val fmM = Array(0,0.05,0.15,0.2, 0.3, 0.35,0.45,0.5,0.5,0.55,0.65,0.7,0.8,0.85,0.95,1.0) // \mu_{OWA} -- 4 elements (Table 6.4 in (Torra & Narukawa,2007)) val fmO = Array(0.0,0.3333,0.3333,0.6666,0.3333,0.6666,0.6666,1.0,0.3333,0.6666,0.6666,1.0,0.6666,1.0,1.0,1.0) // \mu_{WOWA} -- 4 elements (Table 6.4 in (Torra & Narukawa,2007)) val fmW = Array(0.0,0.0666,0.2,0.2666,0.4,0.4666,0.6,0.6666,0.6666,0.7333,0.8666,0.9333,1.0,1.0,1.0,1.0) // ----------------------------------------------------------------------------------- // Auxiliary functions // ----------------------------------------------------------------------------------- // // Function: return an Array[Int] with the binary representation of a positive integer // Input: // n: integer // Output: // Array[Int]: vector representing the number // Example: // int2Vect(11) val int2Vect: ((Int) => Array[Int]) = (n) => { if (n < 2) { Array (n) } else { int2Vect(n/2) :+ (n%2) } } // Function: an Array[Int] of size len with the binary representation of a positive integer // Input: // n: integer // len: the size of the output array // Output: // Array[Int]: vector representing the number // | an exception of type IllegalArgumentException if size is too short // Example: // int2VectFixedSize(5,10); int2VectFixedSize(8,4); // int2VectFixedSize(0,1); // int2VectFixedSize(0,0); int2VectFixedSize(8,3) // Exception cases val int2VectFixedSize: ((Int,Int) => Array[Int]) = (n,len) => { val vec = int2Vect(n) // this vector has a zero in the first position // val vec = ve0.slice(1,ve0.length) if ((len==0) || (len-vec.length)<0) { throw new IllegalArgumentException("arg 2: lenInt) = (vec) => { vec.foldLeft(0)((a,b)=>(a*2+b)) } // Function: given an "boolean" (0 or 1) array and a set of elements // select the set of elements when the "boolean" is 1. // Input: // vec: Array[Int] an array of integers with 0 and 1 // X: Array[Int] the set of elements that will be used for selection // Output: // a list of elements selected // Example: // vect2set(Array(1,0,1,1),Array(10,20,30,40)) val vect2set: ((Array[Int], Array[Int]) => List[Int]) = (vec, X) => { if (vec.length==0) { List.empty } else if (vec.head==1) { X.head::vect2set(vec.tail, X.tail) } else { vect2set(vec.tail, X.tail) } } // Function: // it orders the vector fxO from lowest to largest, and swaps XO accordingly // *Note*: this function does not destroy the original X, fx // Input: // XO: Array[Int]: vector of values original // fxO: Array[Double]: vector of values original to be ordered // (represents a function on the elements in XO) // Output: // (X, fx): the elements of fx are ordered from lowest to largest, // and X is reordered so fx are aligned with X. // Example: // orderFXandX (Array.range(0,5),Array(0.1,0.6,0.2,0.3,0.7)) val orderFXandX: ((Array[Int], Array[Double]) => (Array[Int], Array[Double])) = (XO, fxO) => { var X = XO.clone var fx = fxO.clone var i = 0 while (ifx(j)) { var auxD = fx(i); fx(i)=fx(j); fx(j)=auxD var auxI = X(i); X(i)=X(j); X(j)=auxI } j=j+1 } i=i+1 } (X,fx) } // Functions: print a fuzzy measure / the value of the measure of a single set // Input: // fm: the fuzzy measure // len: length of the array to represent the set of the fuzzy measures // (or setIndex: integer representing the set, measure of the set, len) // Output: // only side effects: a row for each set in the power set, with the set and the fuzzy measure for that set. // Example: // val fm1 = Array(0,0,0.1,0.2, 1,1,1,1); printFM(fm1,4) // printOneSetsMeasure(4,0.94,5) val printFM: ((Array[Double], Int) => Unit) = (fm, len) => { (0 to fm.length-1) foreach {(i)=>{ println("<"++int2VectFixedSize(i,len).mkString("[", ",", "]:")++fm(i).toString++">") }} } val printOneSetsMeasure: ((Int, Double, Int) => Unit) = (setIndex, measure, len) => { println("<"++int2VectFixedSize(setIndex,len).mkString("[", ",", "]:")++measure.toString++">") } // Functions: compute the Choquet integral // Input: // f: function to be integrated // fm: fuzzy measure // *NOTE* It is pressumed that the order of the elements in f is the same used in the measure // Output: // the Choquet integral of f with respect to fm // Example: // choquetIntegral(Array(0,0.5,1,1),fmW) // Output 0.4666 // choquetIntegral(Array(0.5,0.5,0.5,0.5),fmW) // Output 0.5 // choquetIntegral(Array(1,0.5,0,0.5),fmW) // Output 0.8333 // choquetIntegral(Array(1,0.5,0.5,0.5),fmW) // Output 0.8333 // choquetIntegral(Array(0.5,1,1,0.5),fmW) // Output 0.8 // choquetIntegral(Array(1,1,0.5,1),fmW) // Output 1.0 val choquetIntegral: ((Array[Double], Array[Double]) => Double) = (f, fm) => { val items = Array.range(0,f.length) // X={0,...,N-1} val (itemsOrd, fOrd) = orderFXandX (items, f.clone) // f_{s(i)} val setItems = Array.fill[Int](f.length)(1) // A_{s(1)} = all elements val fmOfSetItems = vect2int(setItems) printOneSetsMeasure(fmOfSetItems,fm(fmOfSetItems),10) var total = fOrd(0) * fm(fmOfSetItems); var i = 1; print(total) while (i { fmW(vect2int(set))}) // Output 0.4666 // choquetIntegralWithFunction(Array(0.5,0.5,0.5,0.5),(set) => { fmW(vect2int(set))}) // Output 0.5 // choquetIntegralWithFunction(Array(1,0.5,0,0.5),(set) => { fmW(vect2int(set))}) // Output 0.8333 // choquetIntegralWithFunction(Array(1,0.5,0.5,0.5),(set) => { fmW(vect2int(set))}) // Output 0.8333 // choquetIntegralWithFunction(Array(0.5,1,1,0.5),(set) => { fmW(vect2int(set))}) // Output 0.8 // choquetIntegralWithFunction(Array(1,1,0.5,1),(set) => { fmW(vect2int(set))}) // Output 1.0 val choquetIntegralWithFunction: ((Array[Double], (Array[Int]=>Double)) => Double) = (f, fm) => { val items = Array.range(0,f.length) // X={0,...,N-1} val (itemsOrd, fOrd) = orderFXandX (items, f.clone) // f_{s(i)} val setItems = Array.fill[Int](f.length)(1) // A_{s(1)} = all elements printOneSetsMeasure(vect2int(setItems),fm(setItems),15) var total = fOrd(0) * fm(setItems); var i = 1; print(total) while (i