/** * 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 CertainTrustSimple extends Observable { private double c, t, f, r, s, doc; private int n = 1, weight = 2; //=========== Constructors ================= /** * Constructs a CertainTrustSimple object with predefined n value. * @param n - maximal number of expected evidence */ public CertainTrustSimple(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 CertainTrustSimple object with predefined c, t, f, n values. * @param c - certainty * @param t - average rating * @param f - initial trust value */ public CertainTrustSimple(double t, double c, double f) { this.f = f; setTC(t, c); } /** * Constructs a CertainTrustSimple 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 CertainTrustSimple(double t, double c, double f, double doc) { if (n > 0) { if (f <= 1 && f >= 0) { this.f = f; 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 ================= /** * 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; 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"); } //=========== Internal Calculations ========== //=========== Getters ================= public double getC() { return c; } public double getT() { return t; } public double getF() { return f; } public double getDoC() { return doc; } public double getExpectation() { return t*c + (1-c)*f; } //=========== Logic ================= /** * Computes OR function for this CertainTrustSimple 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 CertainTrustSimple OR(CertainTrustSimple 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)) resC = c1 + c2 - c1*c2; 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); CertainTrustSimple result = new CertainTrustSimple(resT, resC, resF,0); return result; } /** * Computes OR function for this CertainTrustSimple 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 CertainTrustSimple OR(CertainTrustSimple ...args) { CertainTrustSimple result = clone(); for (CertainTrustSimple 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 CertainTrustSimple 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 CertainTrustSimple AND(CertainTrustSimple 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)) //avoid division by 0 resC = c1 + c2 - c1*c2; 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); CertainTrustSimple result = new CertainTrustSimple(resT, resC, resF,0); return result; } /** * Computes AND function for this CertainTrustSimple 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 CertainTrustSimple AND(CertainTrustSimple ...args) { CertainTrustSimple result = clone(); for (CertainTrustSimple 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 CertainTrustSimple object. * For detailed information see CertainLogic: A Logic for Modeling Trust and Uncertainty * @return - NOT of this CertainTrustSimple object. */ public CertainTrustSimple NOT(){ return new CertainTrustSimple(getC(), adjustValue(1 - getT()), adjustValue(1 - getF())); } /** * an internal implementation of fusion function. * Is called by wFusion and cFusion * @param args - an array of CertainTrustSimple objects * @param weights - an integer array of corresponding weights * @param doc - a degree of conflict (always 0 for wFusion) * @return - new CertainTrustSimple object */ private static CertainTrustSimple internalFusion(CertainTrustSimple[] 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; } //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 CertainTrustSimple(resT, resC, resF, doc); } /** * Performs weighted fusion for an array of CertainTrustSimple 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 CertainTrustSimple objects. * Arrays must be non-empty * Either all of CertainTrustSimple must be of certainty 1 or none of them. * @param args - an array of CertainTrustSimple objects * @param weights - an integer array of corresponding weights * @return - new CertainTrustSimple object */ public static CertainTrustSimple wFusion(CertainTrustSimple[] 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 (CertainTrustSimple objects) and takes it into consideration while performing fusion. * The degree of conflict is then saved in the resulting CertainTrustSimple object and may be checked with getDoC() function. * @param args - an array of CertainTrustSimple objects * @param weights - an integer array of corresponding weights * @return - new CertainTrustSimple object */ public static CertainTrustSimple cFusion(CertainTrustSimple[] 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 CertainTrustSimple object and the specified argument. Result is returned as a new object, * argument and this CertainTrustSimple 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 - CertainTrustSimple object * @return - result of CONSENSUS computation for this object and an argument. */ private CertainTrustSimple CONSENSUS(CertainTrustSimple 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)) //avoid division by 0 resC = (c1+c2-2*c1*c2)/(1-c1*c2); else resC = (c1+c2-2*c1*c2)/(1-c1*c2); if (almostEqual(resC, 0)) resT = 0.5; else if (almostEqual(resF, 1)) //avoid division by 0 resT = (c1*t1*(1-c2)+c2*t2*(1-c1))/(c1*(1-c2)+c2*(1-c1)); else resT = (c1*t1*(1-c2)+c2*t2*(1-c1))/(c1*(1-c2)+c2*(1-c1)); resT = adjustValue(resT); resC = adjustValue(resC); resF = adjustValue(resF); CertainTrustSimple result = new CertainTrustSimple(resT, resC, resF, 0); return result; } /** * Computes CONSENSUS function for this CertainTrustSimple object and the specified arguments. * Result is returned as a new object, arguments and this CertainTrustSimple object remain unchanged. * Example: a.CONSENSUS(b, c, d) returns new CertainTrustSimple 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 CertainTrustSimple CONSENSUS(CertainTrustSimple ...args) { CertainTrustSimple result = clone(); for (CertainTrustSimple 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 CertainTrustSimple object and the specified argument. Result is returned as a new object, * argument and this CertainTrustSimple 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 CertainTrustSimple DISCOUNTING(CertainTrustSimple 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)) 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); CertainTrustSimple result = new CertainTrustSimple(resT, resC, resF, 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 CertainTrustSimple DISCOUNTING(CertainTrustSimple ...args) { CertainTrustSimple result = clone(); for (CertainTrustSimple 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 CertainTrustSimple clone() { CertainTrustSimple copy = new CertainTrustSimple(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; } }