/** * CertainTrust SDK * * Implements the computational trust model "CertainTrust" * in Java. * See for further details. * * * Telecooperation Department, Technische Universit�t Darmstadt * * * Prof. Dr. Max Mühlhäuser * Florian Volk * * * @author Maria Pelevina * @author David Kalnischkies * @version 1.1 */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package CertainTrust; import java.util.Observable; /** * * t - average rating value, [0; 1], from very negative to very positive * c - certainty value, [0; 1] from low certainty (no evidence) to the maximal maximal certainty. * f - initial trust value * w - weight * r - number of positive evidence * s - number of negative evidence * n - maximal number of expected evidence * doc - degree of conflict * */ public class CertainTrust extends Observable { private double c, t, f, r, s, doc; private String name; private int n, weight = 2; //=========== Constructors ================= /** * Constructs a CertainTrust object with predefined n value. * @param n - maximal number of expected evidence */ public CertainTrust(int n) { if (n > 0) { this.n = n; c = 0; t = 0.5; f = 0.5; r = 0; s = 0; } else throw new IllegalArgumentException("N should be greater than 0. Entered n = " + n + "\n"); } /** * Constructs a CertainTrust object with predefined r, s, n values. * @param r - number of positive evidence * @param s - number of negative evidence * @param n - maximal number of expected evidence */ public CertainTrust(double r, double s, int n) { if (n > 0) { this.n = n; this.c = 0; this.t = 0.5; this.f = 0.5; this.doc = 0; setRS(r, s); } else throw new IllegalArgumentException("N should be greater than 0. Entered n = " + n + "\n"); } /** * Constructs a CertainTrust object with predefined c, t, f, n values. * @param c - certainty * @param t - average rating * @param f - initial trust value * @param n - maximal number of expected evidence */ public CertainTrust(double t, double c, double f, int n) { this(t,c,f,n,0); } /** * Constructs a CertainTrust object with predefined c, t, f, n values. * @param c - certainty * @param t - average rating * @param f - initial trust value * @param n - maximal number of expected evidence * @param doc - initial degree of conflict */ private CertainTrust(double t, double c, double f, int n, double doc) { if (n > 0) { if (f <= 1 && f >= 0) { this.n = n; this.f = f; this.r = 0; this.s = 0; this.doc = doc; setTC(t, c); } else throw new IllegalArgumentException("f should lie within [0;1]. Entered f = " + f + "\n"); } else throw new IllegalArgumentException("N should be greater than 0. Entered n = " + n + "\n"); } //=========== Setters ================= /** * Resets N value. Renormalises r and s values, recalculates c and t accordingly. * @param n - new maximal number of expected evidence */ public void setN(int n) { if (n > 0) { this.n = n; normaliseRS(); calculateRStoTC(); setChanged(); notifyObservers(); } else throw new IllegalArgumentException("N should be greater than 0. Entered n = " + n + "\n"); } /** * Sets f value. * @param f - initial trust value. */ public void setF(double f) { if (f >= 0 && f <= 1) { this.f = f; setChanged(); notifyObservers(); } else throw new IllegalArgumentException("f should lie within [0;1]. Entered f = " + f + "\n"); } /** * Sets Distance of Conflict value. * @param doc is the new value for DoC */ public void setDoC(double doc) { if (doc > 0) { this.doc = doc; } else throw new IllegalArgumentException("DoC should be greater than 0. Entered DoC = " + doc + "\n"); } /** * Sets c and t values. Recalculates r and s values accordingly. * @param t - new average trust value * @param c - new certainty value */ public void setTC(double t, double c) { if (c >= 0 && c <= 1) { if (t >= 0 && t <= 1) { this.c = c; this.t = t; calculateTCtoRS(); setChanged(); notifyObservers(); } else throw new IllegalArgumentException("t should be greater than 0. Entered t = " + t + "\n"); } else throw new IllegalArgumentException("c should lie within [0;1]. Entered c = " + c + "\n"); } /** * Sets r and s values. Recalculates c and t values accordingly. * @param r - new number of positive evidence * @param s - new number of negative evidence */ public void setRS(double r, double s) { if (r >= 0) { if (s >= 0) { this.r = r; this.s = s; normaliseRS(); calculateRStoTC(); setChanged(); notifyObservers(); } else throw new IllegalArgumentException("s should be positive. Entered s = " + s + "\n"); } else throw new IllegalArgumentException("r should be positive. Entered r = " + r + "\n"); } /** * Sets name value. * @param name - name of object. */ public void setName(String s) { this.name = s; } /** * Add some positive evidence to r. * @param posEvidence - number of new positive evidences */ public void addR(int posEvidence) { if (posEvidence >= 0) { r += posEvidence; normaliseRS(); calculateRStoTC(); setChanged(); notifyObservers(); } else throw new IllegalArgumentException("Number of positive evidences should be positive. Entered " + posEvidence + "\n"); } /** * Add some negative evidence to s. * @param negEvidence - number of new negative evidences */ public void addS(int negEvidence) { if (negEvidence >= 0) { s += negEvidence; normaliseRS(); calculateRStoTC(); setChanged(); notifyObservers(); } else throw new IllegalArgumentException("Number of negative evidences should be positive. Entered " + negEvidence + "\n"); } //=========== Internal Calculations ========== /** * Normalises r and s values according to n - maximal number of expected evidence * Important! Doesn't notify observers. */ private void normaliseRS() { if (r + s > n){ double initR = r; r = r*n / (initR + s); s = s*n / (initR + s); } } /** * Calculates c and t values based on existing r and s values * Important! Doesn't notify observers. */ private void calculateRStoTC() { c = n * (r + s) / ( weight*(n-r-s) + n*(r+s)); if (c == 0) t = 0.5; else t = r / (r + s); } /** * Calculates r and s values based on existing c and t values * Important! Doesn't notify observers. */ private void calculateTCtoRS() { if (c == 0) { r = 0; s = 0; t = 0.5; } else { r = (2*c*weight*n*t) / (2*c*weight + n - c*n); s = (2*c*weight*n - 2*c*weight*n*t) / (2*c*weight + n - c*n); } } //=========== Getters ================= public double getC() { return c; } public double getT() { return t; } public double getF() { return f; } public double getR() { return r; } public double getS() { return s; } public int getN() { return n; } public double getDoC() { return doc; } public String getName() { return name; } public double getExpectation() { return t*c + (1-c)*f; } //=========== Logic ================= /** * Computes OR function for this CertainTrust object and the specified argument. Result is returned as a new object, * argument and this CertainTrust object remain unchanged. * N values of both objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param arg - CertainTrust object * @return - result of OR computation for this object and an argument. */ private CertainTrust OR(CertainTrust arg){ double c1 = getC(); double t1 = getT(); double f1 = getF(); double c2 = arg.getC(); double t2 = arg.getT(); double f2 = arg.getF(); double resT = 0.5, resF = 0.5, resC = 0; if (this.getN() != arg.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); resF = f1 + f2 - f1*f2; if (almostEqual(resF, 0)) { //--------Modified by Debashis----------------// f1 = 0.99999; f2 = 0.99999; resF = f1 + f2 - f1*f2; resC = c1 + c2 - c1*c2- (c1*f2*(1-c2)*(1-t1)+c2*f1*(1-c1)*(1-t2)) / resF; } else resC = c1 + c2 - c1*c2 - (c1*f2*(1-c2)*(1-t1)+c2*f1*(1-c1)*(1-t2)) / resF; if (almostEqual(resC, 0)) resT = 0.5; else resT = (1/resC) * (c1*t1 + c2*t2 - c1*c2*t1*t2); resT = adjustValue(resT); resC = adjustValue(resC); resF = adjustValue(resF); CertainTrust result = new CertainTrust(resT, resC, resF, n, 0); return result; } /** * Computes OR function for this CertainTrust object and the specified arguments. * Result is returned as a new object, arguments and this CertainTrust object remain unchanged. * Example: a.OR(b, c, d) returns new CertainTrust object that equals a OR b OR c OR d. * Multiple arguments allowed, but not less than one. * N values of all objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param args - arguments * @return - result of OR computation for this object and all arguments. */ public CertainTrust OR(CertainTrust ...args) { CertainTrust result = clone(); for (CertainTrust m: args) { if (n != m.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); result = result.OR(m); } return result; } /** * Computes AND function for this CertainTrust object and the specified argument. Result is returned as a new object, * argument and this CertainTrust object remain unchanged. * N values of both objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param arg - CertainTrust object * @return - result of AND computation for this object and an argument. */ private CertainTrust AND(CertainTrust arg){ double c1 = getC(); double f1 = getF(); double t1 = getT(); double c2 = arg.getC(); double f2 = arg.getF(); double t2 = arg.getT(); double resC = 0, resT = 0.5, resF = 0.5; if (n != arg.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); resF = f1*f2; if (almostEqual(resF, 1)) { //--------Modified by Debashis----------------// f1 = 0.99999; f2 = 0.99999; resF = f1*f2; resC = c1 + c2 - c1*c2- (c2*t2*(1-c1)*(1-f1)+c1*t1*(1-c2)*(1-f2)) / (1 - resF); } else resC = c1 + c2 - c1*c2 - (c2*t2*(1-c1)*(1-f1)+c1*t1*(1-c2)*(1-f2)) / (1 - resF); if (almostEqual(resC, 0)) resT = 0.5; else if (almostEqual(resF, 1)) //avoid division by 0 resT = (1/resC) * (c1*t1*c2*t2); else resT = (1/resC) * ((c1*t1*c2*t2) + (c1*f2*t1*(1-c2)*(1-f1)+c2*f1*t2*(1-c1)*(1-f2)) / (1 - resF)); resT = adjustValue(resT); resC = adjustValue(resC); resF = adjustValue(resF); CertainTrust result = new CertainTrust(resT, resC, resF, n, 0); return result; } /** * Computes AND function for this CertainTrust object and the specified arguments. * Result is returned as a new object, arguments and this CertainTrust object remain unchanged. * Example: a.AND(b, c, d) returns new CertainTrust object that equals a AND b AND c AND d. * Multiple arguments allowed, but not less than one. * N values of all objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param args - arguments * @return - result of AND computation for this object and all arguments. */ public CertainTrust AND(CertainTrust ...args) { CertainTrust result = clone(); for (CertainTrust m: args) { if (n != m.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); result = result.AND(m); } return result; } /** * Returns NOT of this CertainTrust object. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @return - NOT of this CertainTrust object. */ public CertainTrust NOT(){ return new CertainTrust(getC(), adjustValue(1 - getT()), adjustValue(1 - getF()), n, 0); } /** * an internal implementation of fusion function. * Is called by wFusion and cFusion * @param args - an array of CertainTrust objects * @param weights - an integer array of corresponding weights * @param doc - a degree of conflict (always 0 for wFusion) * @return - new CertainTrust object */ private static CertainTrust internalFusion(CertainTrust[] args, int[] weights, double doc) { double resC, resT, resF; boolean allOne = true; boolean allZero = true; boolean allWeightsZero = true; boolean atLeastOne1 = false; int arrLength = args.length; // set the flags about C and Weight values for (int i = 0; i < arrLength; i++) if (args[i].getC() != 1) { allOne = false; i = arrLength; } for (int i = 0; i < arrLength; i++) if (args[i].getC() != 0) { allZero = false; i = arrLength; } for (int i = 0; i < arrLength; i++) if (weights[i] != 0) { allWeightsZero = false; i = arrLength; } for (int i = 0; i < arrLength; i++) if (args[i].getC() == 1) { atLeastOne1 = true; i = arrLength; } //-------------Modified by Debashis-----------------// if(atLeastOne1 && !allOne){ for (int i = 0; i < arrLength; ++i) if (args[i].getC() == 1) { args[i].setTC(args[i].getT(),0.99999); } } //Calculate T and C // 1. all C's = 1 if (allOne) { // set C resC = 1 * (1 - doc); // set T if (allWeightsZero) {// save some calculation time resT = 0; } else { // or use the function double numeratorT = 0, denominatorT = 0; for (int i = 0; i < arrLength; i++) { numeratorT += weights[i] * args[i].getT(); denominatorT += weights[i]; } resT = numeratorT/denominatorT; } } else { if (atLeastOne1) throw new IllegalStateException("Illeagal arguments. Either all C values must equal 1 or none of them. Operation not allowed \n"); // 2. Any other combination if (allWeightsZero) { // save some calculation time resT = 0; resC = 0; } else { // or use the function double numeratorT = 0, denominatorT = 0, numeratorC = 0, denominatorC = 0, mult; for (int i = 0; i < arrLength; i++) { mult = 1; for (int j = 0; j < arrLength; j++) // Count the product for each sum element if (j != i) mult *= 1 - args[j].getC(); numeratorT += weights[i] * args[i].getT() * args[i].getC() * mult; denominatorT += weights[i] * args[i].getC() * mult; denominatorC += weights[i] * mult; } numeratorC = denominatorT; resC = (numeratorC/denominatorC) * (1 - doc); if (allZero) resT = 0.5; else resT = numeratorT/denominatorT; } // Special case for T if (allZero) resT = 0.5; } // Calculate F if (allWeightsZero) resF = 0; else { double numerator = 0, denominator = 0; for (int i = 0; i < arrLength; i ++) { numerator += weights[i] * args[i].getF(); denominator += weights[i]; } resF = numerator/denominator; } return new CertainTrust(resT, resC, resF, args[0].getN(), doc); } /** * Performs weighted fusion for an array of CertainTrust objects in correspondence with * an array of weights. Returns new CertainTrust object. * Requirements: N values of CertainTrust objects must be equal. * Number of weights should equal the number of CertainTrust objects. * Arrays must be non-empty * Either all of CertainTrust must be of certainty 1 or none of them. * @param args - an array of CertainTrust objects * @param weights - an integer array of corresponding weights * @return - new CertainTrust object */ public static CertainTrust wFusion(CertainTrust[] args, int[] weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length != 0) { boolean equalNs = true; int N = args[0].getN(); for (int i = 1; i < args.length; i++) if (N != args[i].getN()) { equalNs = false; i = args.length; } //and all N's of TC's must be equal if (equalNs) { return internalFusion(args, weights, 0); } throw new IllegalStateException("Different N values. Operation not allowed. \n"); } throw new IllegalStateException("Arrays are empty. Operation not allowed. \n"); } throw new IllegalStateException("Different lengths of arrays. Operation not allowed. \n"); } /** * Conflicted Fusion is a variation of weighted fusion, which additionally computes the degree of conflict * between given opinions (CertainTrust objects) and takes it into consideration while performing fusion. * The degree of conflict is then saved in the resulting CertainTrust object and may be checked with getDoC() function. * @param args - an array of CertainTrust objects * @param weights - an integer array of corresponding weights * @return - new CertainTrust object */ public static CertainTrust cFusion(CertainTrust[] args, int[] weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length != 0) { boolean equalNs = true; int N = args[0].getN(); for (int i = 1; i < args.length; i++) if (N != args[i].getN()) { equalNs = false; i = args.length; } //and all N's of TC's must be equal if (equalNs) { double denominator = args.length*(args.length - 1) / 2; double numerator = 0; for (int i = 0; i < args.length; i++) for (int j = i; j < args.length; j++) numerator += Math.abs(args[i].getT() - args[j].getT()) * args[i].getC() * args[j].getC()*(1 - Math.abs((double)(weights[i] - weights[j])/(weights[i] + weights[j]))); double doc = numerator/denominator; return internalFusion(args, weights, doc); } throw new IllegalStateException("Different N values. Operation not allowed. \n"); } throw new IllegalStateException("Arrays are empty. Operation not allowed. \n"); } throw new IllegalStateException("Different lengths of arrays. Operation not allowed. \n"); } /** * Computes CONSENSUS function for this CertainTrust object and the specified argument. Result is returned as a new object, * argument and this CertainTrust object remain unchanged. * N values of both objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param arg - CertainTrust object * @return - result of CONSENSUS computation for this object and an argument. */ private CertainTrust CONSENSUS(CertainTrust arg){ double c1 = getC(); double f1 = getF(); double t1 = getT(); double c2 = arg.getC(); double f2 = arg.getF(); double t2 = arg.getT(); double resC = 0, resT = 0.5, resF = 0.5; if (n != arg.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); double tempC = c1*c2; if (this.almostEqual(tempC, 1)){ //avoid division by 0 c1 = 0.99999; c2 = 0.99999; } resF = (f1*c1*(1-c2) + f2*c2*(1-c1))/(c1+c2-2*c1*c2); resC = (c1+c2-2*c1*c2)/(1-c1*c2); resT = (c1*t1*(1-c2)+c2*t2*(1-c1))/(c1+c2-2*c1*c2); resT = adjustValue(resT); resC = adjustValue(resC); resF = adjustValue(resF); CertainTrust result = new CertainTrust(resT, resC, resF, n, 0); return result; } /** * Computes CONSENSUS function for this CertainTrust object and the specified arguments. * Result is returned as a new object, arguments and this CertainTrust object remain unchanged. * Example: a.CONSENSUS(b, c, d) returns new CertainTrust object that equals a CONSENSUS b CONSENSUS c CONSENSUS d. * Multiple arguments allowed, but not less than one. * N values of all objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param args - arguments * @return - result of CONSENSUS computation for this object and all arguments. */ public CertainTrust CONSENSUS(CertainTrust ...args) { CertainTrust result = clone(); for (CertainTrust m: args) { if (n != m.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); result = result.CONSENSUS(m); } return result; } /** * Computes DISCOUNTING function for this CertainTrust object and the specified argument. Result is returned as a new object, * argument and this CertainTrust object remain unchanged. * N values of both objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param arg - CertainTrust object * @return - result of DISCOUNTING computation for this object and an argument. */ private CertainTrust DISCOUNTING(CertainTrust arg){ double c1 = getC(); double f1 = getF(); double t1 = getT(); double c2 = arg.getC(); double f2 = arg.getF(); double t2 = arg.getT(); double resC = 0, resT = 0.5, resF = 0.5; if (n != arg.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); resF = f2; if (almostEqual(resF, 1)) resC = t1*c1*c2; else resC = t1*c1*c2; if (almostEqual(resC, 0)) resT = 0.5; else if (almostEqual(resF, 1)) resT = t2; else resT = t2; resT = adjustValue(resT); resC = adjustValue(resC); resF = adjustValue(resF); CertainTrust result = new CertainTrust(resT, resC, resF, n, 0); return result; } /** * Computes DISCOUNTING function for this CertainTrust object and the specified arguments. * Result is returned as a new object, arguments and this CertainTrust object remain unchanged. * Example: a.DISCOUNTING(b, c, d) returns new CertainTrust object that equals a DISCOUNTING b DISCOUNTING c DISCOUNTING d. * Multiple arguments allowed, but not less than one. * N values of all objects should be equal. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @param args - arguments * @return - result of DISCOUNTING computation for this object and all arguments. */ public CertainTrust DISCOUNTING(CertainTrust ...args) { CertainTrust result = clone(); for (CertainTrust m: args) { if (n != m.getN()) throw new IllegalStateException("Different N values. Operation not allowed. \n"); result = result.DISCOUNTING(m); } return result; } //=========== Additional Functions ================= @Override public CertainTrust clone() { CertainTrust copy = new CertainTrust(n); copy.c = this.c; copy.t = this.t; copy.f = this.f; copy.r = this.r; copy.s = this.s; copy.doc = this.doc; return copy; } /** * Adjusts the value of a into the allowed range [0,1]. * @param a - value to be adjusted */ private double adjustValue(double a) { return Math.max(Math.min(a, 1), 0); } /** * compares two double values using an epsilon * @param value - given value * @param target - expected value * @return */ private boolean almostEqual(double value, double target) { return Math.abs(value - target) < 1E-10; } }