/**
* 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;
}
}