## Software: ## (c) Vicenç Torra ## Current version: 20250110 ## ## References: ## ## V. Torra, Differentially private Choquet integral: extending mean, ## median, and order statistics, Int. J. of Information Security, 2025. ## ## This software describes the definitions and experiments in the paper ## These other files are needed: ## exec(open("prog.vectors.matrices.web.txt").read()) ## exec(open("prog.choquet.web.txt").read()) ## Data for measure identification ## ("ML", "P", "M", "L", "G", "Subjective evaluation") ## (Table 8.5 in (Torra & Narukawa,2007)) data85 = [ [ 0.8 , 0.9 , 0.8 , 0.1 , 0.1, 0.7], [ 0.7 , 0.6 , 0.9 , 0.2 , 0.3, 0.6], [ 0.7 , 0.7 , 0.7 , 0.2 , 0.6, 0.6], [ 0.6 , 0.9 , 0.9 , 0.4 , 0.4, 0.8], [ 0.8 , 0.6 , 0.3 , 0.9 , 0.9, 0.8], [ 0.2 , 0.4 , 0.2 , 0.8 , 0.1, 0.3], [ 0.1 , 0.2 , 0.4 , 0.1 , 0.2, 0.1], [ 0.3 , 0.3 , 0.3 , 0.8 , 0.3, 0.4], [ 0.5 , 0.2 , 0.1 , 0.2 , 0.1, 0.3], [ 0.8 , 0.2 , 0.2 , 0.5 , 0.1, 0.5]] ## Table 1 (Torra, IJIS 2025): data85_FM ## Its Mobius transform corresponds to variable: data85_Mob ## This measure corresponds to the arbitrary fuzzy measure that, ## using a Choquet integral, minimizes the MSE of data85 ## Computations to obtain this measure (as well as others needed ## in the paper): ## CASE Arbitrary fuzzy measure: needed # data85_sol = ciFindMoebiusCIwithMSE(data85) # data85_Mob = data85_sol[0] # Select Mobius transform # data85_FM = fromMoebius2FM (data85_Mob, 5) # Compute the measure # ## CASE OWA: # data85_OWA_sol = ciFindMoebiusOWA (data85) # data85_OWA_Mob = data85_OWA_sol # Select Mobius transform # data85_OWA_FM = fromMoebius2FM (data85_OWA_Mob, 5) # Compute the measure # ## CASE WM: # data85_WM_sol = ciFindMoebius(data85, belief=False, kAdditive=1) # data85_WM_Mob = data85_WM_sol # data85_WM_FM = fromMoebius2FM (data85_WM_Mob, 5) # Compute the measure ## The outputs of these computations are: data85_FM = [0, 0.4400477403350282, 0.1974238785124513, 0.6292891762439453, 9.66178074636371e-09, 0.5808861386077339, 0.5614206325549257, 0.7045206163143192, 0.20000279457278955, 0.5709265131519488, 0.200003385204304, 0.695759750928361, 0.7049582571729998, 0.704958281251926, 0.7320187927269185, 0.815718093171686, 0.4386394926253521, 0.6084067226318013, 0.6196549121646089, 0.8066594278560638, 0.6997209433401278, 0.7485198992125616, 0.7442204916590274, 0.8593844607608435, 0.5859047611338524, 0.7063629129758683, 0.6840815069848343, 0.9191306315310449, 0.8250694626297873, 0.825069489900343, 0.8251166956989862, 1.0000000000000002] data85_OWA_FM = [0, 0.12454827615123037, 0.12454827615123037, 0.7629784826927066, 0.12454827615123037, 0.7629784826927066, 0.7629784826927066, 0.8160208335634254, 0.12454827615123037, 0.7629784826927066, 0.7629784826927066, 0.8160208335634254, 0.7629784826927066, 0.8160208335634254, 0.8160208335634254, 0.816195689700077, 0.12454827615123037, 0.7629784826927066, 0.7629784826927066, 0.8160208335634254, 0.7629784826927066, 0.8160208335634254, 0.8160208335634254, 0.816195689700077, 0.7629784826927066, 0.8160208335634254, 0.8160208335634254, 0.816195689700077, 0.8160208335634254, 0.816195689700077, 0.816195689700077, 0.9999999999999987] data85_WM_FM = [0, 0.03990386997492998, 0.12490420454798423, 0.1648080745229143, 1.8561205548341423e-05, 0.03992243118047832, 0.12492276575353257, 0.16482663572846262, 0.41077774286318536, 0.45068161283811564, 0.5356819474111697, 0.5755858173860976, 0.4107963040687337, 0.45070017404366397, 0.535700508616718, 0.5756043785916459, 0.42439562140835463, 0.46429949138328536, 0.549299825956339, 0.5892036959312688, 0.42441418261390296, 0.4643180525888337, 0.5493183871618873, 0.5892222571368171, 0.8351733642715399, 0.8750772342464709, 0.9600775688195243, 0.9999814387944518, 0.8351919254770882, 0.8750957954520192, 0.9600961300250727, 0.9999999999999998] ## ## Mobius transforms of the measures above ## data85_Mob = [0, 0.4400477403350282, 0.1974238785124513, -0.0081824426035342, 9.66178074636371e-09, 0.14083838861092493, 0.3639967443806936, -0.4296037025830253, 0.20000279457278955, -0.06912402175586901, -0.19742328788093683, 0.13301508974843176, 0.5049554529384295, -0.5117620831111579, -0.33693679945828936, 0.38847033180396895, 0.4386394926253521, -0.27028051032857897, -0.016408458973194522, 0.025419728288539913, 0.2610814410529949, -0.26180666274494035, -0.5005126156010509, 0.47873143012740216, -0.052737526064289234, 0.019814943591435732, 0.11458461419266196, -0.035661402729242994, -0.5268722021572702, 0.5122722326737129, 0.3753231578968634, -0.37730575502208147] data85_OWA_Mob = [0, 0.12454827615123037, 0.12454827615123037, 0.5138819303902459, 0.12454827615123037, 0.5138819303902459, 0.5138819303902459, -1.0992697860610035, 0.12454827615123037, 0.5138819303902459, 0.5138819303902459, -1.0992697860610035, 0.5138819303902459, -1.0992697860610035, -1.0992697860610035, 1.631790146997694, 0.12454827615123037, 0.5138819303902459, 0.5138819303902459, -1.0992697860610035, 0.5138819303902459, -1.0992697860610035, -1.0992697860610035, 1.631790146997694, 0.5138819303902459, -1.0992697860610035, -1.0992697860610035, 1.631790146997694, -1.0992697860610035, 1.631790146997694, 1.631790146997694, -1.9278135590370478] data85_WM_Mob = [0, 0.03990386997492998, 0.12490420454798423, 9.350385030207725e-17, 1.8561205548341423e-05, -8.714974738137353e-19, 1.3453465206921525e-18, -1.980223106155586e-18, 0.41077774286318536, 2.6362156974323834e-16, 9.241388504140805e-17, -2.464188384388479e-15, 1.7195725470170128e-18, -9.427917679415164e-19, -1.3012074162498261e-18, -7.854484774348779e-19, 0.42439562140835463, 6.986371389462427e-16, 7.926376886726009e-17, -1.0078089855645241e-15, 1.2306523425062776e-18, -1.9881365984243056e-19, -6.407472200848711e-20, 9.031281449542025e-19, -1.4556576088703035e-16, 5.4921689303835186e-17, 2.874080784547811e-17, -8.695766588882552e-17, -3.903940014170042e-19, 2.3372068627331533e-18, 1.0392798822826667e-18, -1.655833087245139e-18] data85_AM_FM = ciBuildSymmetric ([0.2,0.2,0.2,0.2,0.2]) data85_AM_Mob = fromFM2Moebius (data85_AM_FM, 5) ## Table 2 (Torra, IJIS 2025): ## It corresponds to the Choquet integral w.r.t. the measure in Table 1 ## Computations for obtaining Table 2: ## data85output = list(map(lambda r: r[:-1]+[ciFromMoebius(r[:-1], data85_Mob)], data85)) data85output = [[0.8, 0.9, 0.8, 0.1, 0.1, 0.6975489032981296], [0.7, 0.6, 0.9, 0.2, 0.3, 0.5999998840453395], [0.7, 0.7, 0.7, 0.2, 0.6, 0.6125347422231161], [0.6, 0.9, 0.9, 0.4, 0.4, 0.7765013696778575], [0.8, 0.6, 0.3, 0.9, 0.9, 0.7999999926549205], [0.2, 0.4, 0.2, 0.8, 0.1, 0.3014818980157399], [0.1, 0.2, 0.4, 0.1, 0.2, 0.17049583005754881], [0.3, 0.3, 0.3, 0.8, 0.3, 0.3987119392562255], [0.5, 0.2, 0.1, 0.2, 0.1, 0.29999999848608916], [0.8, 0.2, 0.2, 0.5, 0.1, 0.49999999100688697]] ## data85outputO = list(map(lambda r: ciFromMoebius(r[:-1], data85_Mob), data85)) data85outputO = [0.6975489032981296, 0.5999998840453395, 0.6125347422231161, 0.7765013696778575, 0.7999999926549205, 0.3014818980157399, 0.17049583005754881, 0.3987119392562255, 0.29999999848608916, 0.49999999100688697] ## Functions for the experiments and results ## ## Compute the sensitivity of a fuzzy measure (for the Choquet integral) ## sensitivityCI = max max mu(S \cup X )-mu(S) def dpDPsensitivityFM (fm, n): """ Function: Computation of the sensitivity of the fuzzy measure Example: dpDPsensitivityFM(fmW,4) dpDPsensitivityFM(fmM,4) dpDPsensitivityFM(fmO,4) dpDPsensitivityFM(data85_FM,5) ## 0.704958247511219 """ return max(map(lambda iIndex: max(map(lambda aPerm: fm[setIndex2Int(aPerm[:iIndex], n)] - fm[setIndex2Int(aPerm[:iIndex-1], n)], permutations(list(range(0,n))))), range(1, n+1))) def dpDPsensitivityFMv2 (fm, n): """ Function: Computation of the sensitivity of the fuzzy measure Example: dpDPsensitivityFM(fmW,4) dpDPsensitivityFM(fmM,4) dpDPsensitivityFM(fmO,4) dpDPsensitivityFM(data85_FM,5) ## 0.704958247511219 """ mMax = 0 for aPerm in permutations(list(range(0,n))): for iIndex in range(1,n+1): mMax = max(mMax, fm[setIndex2Int(aPerm[:iIndex], n)] - fm[setIndex2Int(aPerm[:iIndex-1], n)]) return mMax def dpDPLaplace (x, p_sensitivity, p_epsilon): """ Function: Add Laplacian noise to a value (according to sensitivity and epsilon to satisfy e-DP) """ b = p_sensitivity/p_epsilon return x + np.random.laplace(0, b) def dpDPLaplaceCI (data, fm_moebius, p_sensitivity, p_epsilon): """ Function: Adding Laplacian noise to multiple records (variable: data) where data also contains an output that is overwritten. (according to sensitivity and epsilon to satisfy e-DP) """ dpData = list(map(lambda r: dpDPLaplace(ciFromMoebius(r[:-1], fm_moebius), p_sensitivity, p_epsilon), data)) return dpData def dpDPLaplace_ED (x, p_sensitivity, p_epsilon, p_delta): """ Function: Add Laplacian noise to a value (according to sensitivity, epsilon and delta to satisfy (e,d)-DP) """ b = p_sensitivity/(p_epsilon-np.log(1-p_delta)) return x + np.random.laplace(0, b) def dpDPLaplaceCI_ED (data, fm_moebius, p_sensitivity, p_epsilon, p_delta): """ Function: Add Laplacian noise to multiple records (variable: data) where data also contains an output that is overwritten. (according to sensitivity, epsilon and delta to satisfy (e,d)-DP) """ dpData = list(map(lambda r: dpDPLaplace_ED(ciFromMoebius(r[:-1], fm_moebius), p_sensitivity, p_epsilon, p_delta), data)) return dpData def dpDPGaussian_ED (x, p_sensitivity_2, p_epsilon, p_delta): """ Function: Add Gaussian noise to a value (according to sensitivity, epsilon and delta to satisfy (e,d)-DP) """ std_sigma = math.sqrt(2*np.log(1.25/p_delta))*(p_sensitivity_2/p_epsilon) return x + np.random.normal(0, std_sigma) def dpDPGaussianCI_ED (data, fm_moebius, p_sensitivity_2, p_epsilon, p_delta): """ Function: Add Gaussian noise to multiple records (variable: data) where data also contains an output that is overwritten. (according to sensitivity, epsilon and delta to satisfy (e,d)-DP) """ dpData = list(map(lambda r: dpDPGaussian_ED(ciFromMoebius(r[:-1], fm_moebius), p_sensitivity_2, p_epsilon, p_delta), data)) return dpData ## Output for Example 5: ## dpDPsensitivityFM(data85_FM,5) ## 0.704958247511219 ## ## ## Sensitivities for all the measures (only Example 5 provided in the paper) # # dpDPsensitivityFM(data85_FM,5) ## 0.704958247511219 # dpDPsensitivityFM(data85_OWA_FM,5) ## 0.6384302065414762 # dpDPsensitivityFM(data85_WM_FM, 5) ## 0.4243956214083554 # dpDPsensitivityFM(data85_AM_FM,5) ## 0.20000000000000007 ## Definitions for building the figures. from scipy.stats import spearmanr ## data: a set of records, each one includes input + output def plotPromig (data, fm_mobius, sensit, myFile="unnamed.eps"): """ Function: Plots correlation coefficients for e-DP using Laplacian noise for different epsilon values """ data_originalOutput = list(map(lambda r: r[-1], data)) print(data_originalOutput) allEps = [0.1,0.2,0.5,0.75,1.0, 2.0, 3.0,4.0,5.0] meanV=[] sdV=[] for eps in allEps: a = [] for i in range(0,50): dp = dpDPLaplaceCI(data, fm_mobius, sensit, eps) sp = spearmanr(data_originalOutput, dp)[0] #print(dp) #print(sp) a = a+[sp] meanV = meanV+[mean(a)] #print(a) sdV = sdV+[statistics.stdev(a)] print(allEps) print(meanV) print(sdV) plt.errorbar(allEps,meanV,sdV) plt.legend() plt.xlabel('epsilon') plt.ylim(-0.4,1.2) plt.ylabel('spearman') plt.title('True vs. noisy ranking') plt.savefig(myFile, format='eps') plt.show() return plt ## data: a set of records, each one includes input + output def plotPromig_ED (data, fm_mobius, sensit, delta, myFile="unnamed.eps"): """ Function: Plots correlation coefficients for (e,d)-DP using Laplacian noise for different epsilon values """ data_originalOutput = list(map(lambda r: r[-1], data)) print(data_originalOutput) allEps = [0.1,0.2,0.5,0.75,1.0, 2.0, 3.0,4.0,5.0] meanV=[] sdV=[] for eps in allEps: a = [] for i in range(0,50): dp = dpDPLaplaceCI_ED(data, fm_mobius, sensit, eps, delta) sp = spearmanr(data_originalOutput, dp)[0] #print(dp) #print(sp) a = a+[sp] meanV = meanV+[mean(a)] #print(a) sdV = sdV+[statistics.stdev(a)] print(allEps) print(meanV) print(sdV) plt.errorbar(allEps,meanV,sdV) plt.legend() plt.xlabel('epsilon') plt.ylim(-0.4,1.2) plt.ylabel('spearman') plt.title('True vs. noisy ranking') plt.savefig(myFile, format='eps') plt.show() return plt ## data: includes input + output def plotPromig_G_ED (data, fm_mobius, sensit, delta, myFile="unnamed.eps"): """ Function: Plots correlation coefficients for (e,d)-DP using Gaussian noise for different epsilon values """ data_originalOutput = list(map(lambda r: r[-1], data)) print(data_originalOutput) allEps = [0.1,0.2,0.5,0.75,1.0] meanV=[] sdV=[] for eps in allEps: a = [] for i in range(0,50): dp = dpDPGaussianCI_ED(data, fm_mobius, sensit, eps, delta) sp = spearmanr(data_originalOutput, dp)[0] #print(dp) #print(sp) a = a+[sp] meanV = meanV+[mean(a)] #print(a) sdV = sdV+[statistics.stdev(a)] print(allEps) print(meanV) print(sdV) plt.errorbar(allEps,meanV,sdV) plt.legend() plt.xlabel('epsilon') plt.ylim(-0.4,1.2) plt.ylabel('spearman') plt.title('True vs. noisy ranking') plt.savefig(myFile, format='eps') plt.show() return plt ## Calculations for the figures in Section 4 of the paper. plotPromig (data85, data85_Mob, dpDPsensitivityFM(data85_FM,5), "fig.data85.fm.gen.eps") ## FIGURE 1 plotPromig (data85, data85_WM_Mob,dpDPsensitivityFM(data85_WM_FM,5), "fig.data85.fm.wm.eps") ## FIGURE 2 plotPromig (data85, data85_OWA_Mob, dpDPsensitivityFM(data85_OWA_FM,5), "fig.data85.fm.sym.eps") ## FIGURE 3 plotPromig (data85, data85_AM_Mob, dpDPsensitivityFM(data85_AM_FM,5), "fig.data85.fm.am.eps") ## FIGURE 4 plotPromig_ED (data85, data85_Mob, dpDPsensitivityFM(data85_FM,5), 0.1, "fig.data85.01.fm.gen.eps") ## FIGURE 5 plotPromig_ED (data85, data85_Mob, dpDPsensitivityFM(data85_FM,5), 0.5, "fig.data85.05.fm.gen.eps") ## FIGURE 6 plotPromig_G_ED (data85, data85_Mob, dpDPsensitivityFM(data85_FM,5), 0.5, "fig.data85.05.Gaus.fm.gen.eps") ## FIGURE 7 ## Computation of the sensitivity of the symmetric measure for the Concrete data set (Section 4) concrete_fHeader, concrete_fRows = readNumericalFileWithHeader("Concrete_DataVarsV1V7.csv") concrete_fMins, concrete_fMaxs, concrete_fRowsI01 = matrixScaleMinMax(concrete_fRows) # CASE OWA: concrete_OWA_sol = ciFindMoebiusOWA (concrete_fRowsI01) concrete_OWA_Mob = concrete_OWA_sol # Select Mobius transform concrete_OWA_FM = fromMoebius2FM (concrete_OWA_Mob, 8) # Compute the measure dpDPsensitivityFM(concrete_OWA_FM,8) ## 0.3273274942726869