/** * CertainTrust SDK * * Implements the computational trust model "CertainTrust" * in JavaScript. * 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/. */ /** * Available Constructors: * - CertainTrust(t, c, f, n) * - CertainTrust(r, s, n) * - CertainTrust(n) * optionally arguments can be preceded by name, e.g. CertainTrust(name, r, s, n) * * 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 */ var CertainTrust = function() { this.weight = 2; this.observers = []; var offset = 0; this.name = ""; if (this._isString(arguments[0])) { this.name = arguments[0]; offset = 1; } if (arguments.length == 4 + offset || arguments.length == 5 + offset) { // CertainTrust(t, c, f, n, doc) // doc is a 'private' parameter this.t = arguments[0 + offset]; this.c = arguments[1 + offset]; this.f = arguments[2 + offset]; this.n = arguments[3 + offset]; this.doc = (arguments.length == 4 + offset) ? 0 : arguments[4 + offset]; this.r = 0; this.s = 0; if (this.n <= 0) throw "N should be greater than 0. Entered n = " + this.n + "\n"; if (this.f < 0 && this.f > 1) throw "f should lie within [0;1]. Entered f = " + this.f + "\n"; if (this.c < 0 && this.c > 1) throw "c should lie within [0;1]. Entered c = " + this.c + "\n"; if (this.t < 0 && this.t > 1) throw "t should lie within [0;1]. Entered t = " + this.t + "\n"; this._calculateTCtoRS(); } else if (arguments.length == 3 + offset) { // CertainTrust(r, s, n) this.n = arguments[2 + offset]; this.c = 0; this.t = 0.5; this.f = 0.5; this.r = arguments[0 + offset]; this.s = arguments[1 + offset]; this.doc = 0; if (this.n <= 0) throw "N should be greater than 0. Entered n = " + this.n + "\n"; if (this.r < 0) throw "r should be positive. Entered r = " + this.r + "\n"; if (this.s < 0) throw "s should be positive. Entered s = " + this.s + "\n"; this._normaliseRS(); this._calculateRStoTC(); } else { if (arguments.length == 1 + offset) { // CertainTrust(n) this.n = arguments[0 + offset]; if (this.n <= 0) throw "N should be greater than 0. Entered n = " + this.n + "\n"; this.c = 0; this.t = 0.5; this.f = 0.5; this.r = 0; this.s = 0; this.doc = 0; } else throw "Illegal number of arguments: " + arguments.length + "\n"; } }; //=========== Getters ================= CertainTrust.prototype.getName = function() { return this.name; }; CertainTrust.prototype.getC = function() { return this.c; }; CertainTrust.prototype.getT = function() { return this.t; }; CertainTrust.prototype.getF = function() { return this.f; }; CertainTrust.prototype.getR = function() { return this.r; }; CertainTrust.prototype.getS = function() { return this.s; }; CertainTrust.prototype.getN = function() { return this.n; }; CertainTrust.prototype.getDoC = function() { return this.doc; }; CertainTrust.prototype.getExpectation = function() { return (this.t * this.c) + ((1 - this.c) * this.f); }; //=========== Setters ================= /** * Resets N value. Renormalises r and s values, recalculates c and t accordingly. * @param n - new maximal number of expected evidence */ CertainTrust.prototype.setN = function(n) { if (n > 0) { this.n = n; this._normaliseRS(); this._calculateRStoTC(); this.notifyObservers(); } else throw "N should be greater than 0. Entered n = " + n + "\n"; }; /** * Sets f value. * @param f - initial trust value. */ CertainTrust.prototype.setF = function(f) { if (f >= 0 && f <= 1) { this.f = f; this.notifyObservers(); } else throw "f should lie within [0;1]. Entered f = " + f + "\n"; }; /** * Sets Degree of Conflict value. * @param doc is the new value for DoC */ CertainTrust.prototype.setDoC = function(doc) { if (doc >= 0) this.doc = doc; else throw "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 */ CertainTrust.prototype.setTC = function(t, c) { if (c >= 0 && c <= 1) { if (t >= 0 && t <= 1) { this.c = c; this.t = t; this._calculateTCtoRS(); this.notifyObservers(); } else throw "t should be greater than 0. Entered t = " + t + "\n"; } else throw "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 */ CertainTrust.prototype.setRS = function(r, s) { if (r >= 0) { if (s >= 0) { this.r = r; this.s = s; this._normaliseRS(); this._calculateRStoTC(); this.notifyObservers(); } else throw "s should be positive. Entered s = " + s + "\n"; } else throw "r should be positive. Entered r = " + r + "\n"; }; /** * Add some positive evidence to r. * @param posEvidence - number of new positive evidences */ CertainTrust.prototype.addR = function(posEvidence) { if (posEvidence >= 0) { this.r += posEvidence; this._normaliseRS(); this._calculateRStoTC(); this.notifyObservers(); } else throw "Number of positive evidences should be positive. Entered " + posEvidence + "\n"; }; /** * Add some negative evidence to s. * @param negEvidence - number of new negative evidences */ CertainTrust.prototype.addS = function(negEvidence) { if (negEvidence >= 0) { this.s += negEvidence; this._normaliseRS(); this._calculateRStoTC(); this.notifyObservers(); } else throw "Number of negative evidences should be positive. Entered " + negEvidence + "\n"; }; //=========== 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. */ CertainTrust.prototype._singleOR = function(arg) { var c1 = this.getC(); var t1 = this.getT(); var f1 = this.getF(); var c2 = arg.getC(); var t2 = arg.getT(); var f2 = arg.getF(); var resT = 0.5, resF = 0.5, resC = 0; if (!this._operationAllowed(this, arg)) return undefined; resF = f1 + f2 - f1*f2; if (this._almostEqual(resF, 0)){ 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 (this._almostEqual(resC, 0)) resT = 0.5; else resT = (1/resC) * (c1*t1 + c2*t2 - c1*c2*t1*t2); resT = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); var result = new CertainTrust(resT, resC, resF, this.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. */ CertainTrust.prototype.OR = function() { var result = this.clone(); for (var i = 0; i < arguments.length; ++i) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singleOR(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. */ CertainTrust.prototype._singleAND = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; resF = f1*f2; if (this._almostEqual(resF, 1)){ //avoid division by 0 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 (this._almostEqual(resC, 0)) resT = 0.5; 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 = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrust(resT, resC, resF, this.n, 0); }; CertainTrust.prototype._adjustValue = function(arg) { return Math.max(Math.min(arg, 1), 0); }; CertainTrust.prototype._almostEqual = function(value, target) { return Math.abs(value - target) < 1E-10; }; CertainTrust.prototype._operationAllowed = function(arg1, arg2) { //and all N's of TC's must be equal /*if (arg1.getN() != arg2.getN()) //Disabled by Debashis C. Ray for AND calculation throw "Different N values. Operation not allowed. \n"; */ return true; } /** * 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. */ CertainTrust.prototype.AND = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singleAND(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. */ CertainTrust.prototype.NOT = function() { var result = this.clone(); result.setTC(1 - this.getT(), this.getC()); result.setF(1 - this.getF()); result.setDoC(0); return result; }; /** * 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 */ CertainTrust.prototype._internalFusion = function(args, weights, doc) { var resC, resT, resF; var allOne = true; var allZero = true; var allWeightsZero = true; var atLeastOne1 = false; var arrLength = args.length; // set the flags about C and Weight values for (var i = 0; i < arrLength; ++i) if (args[i].getC() !== 1) { allOne = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (args[i].getC() !== 0) { allZero = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (weights[i] !== 0) { allWeightsZero = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (args[i].getC() === 1) { atLeastOne1 = true; i = arrLength; } //Calculate T and C // 1. all C's = 1 var numeratorT = 0, denominatorT = 0; if (allOne) { // set C resC = 1 * (1 - doc); // set T if (allWeightsZero) {// save some calculation time resT = 0; } else { // or use the function for (i = 0; i < arrLength; ++i) { numeratorT += weights[i] * args[i].getT(); denominatorT += weights[i]; } resT = numeratorT/denominatorT; } } else { if (atLeastOne1) throw "Illegal arguments. Either all C values must equal 1 or none of them. Operation not allowed\n"; else { // 2. Any other combination if (allWeightsZero) { // save some calculation time resT = 0; resC = 0; } else { // or use the function var numeratorC = 0, denominatorC = 0, mult; for (i = 0; i < arrLength; ++i) { mult = 1; for (var 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 { var numerator = 0, denominator = 0; for (i = 0; i < arrLength; ++i) { numerator += weights[i] * args[i].getF(); denominator += weights[i]; } resF = numerator/denominator; } var result = args[0].clone(); result.setTC(resT, resC); result.setF(resF); result.setDoC(doc); return result; }; /** * 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 */ CertainTrust.prototype.wFusion = function(args, weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length !== 0) { for (var i = 1; i < args.length; ++i) if (!this._operationAllowed(args[0], args[i])) return undefined; return this._internalFusion(args, weights, 0); } else throw "Arrays are empty. Operation not allowed. \n"; } else throw "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 */ CertainTrust.prototype.cFusion = function(args, weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length !== 0) { for (var i = 1; i < args.length; ++i) if (!this._operationAllowed(args[0], args[i])) return undefined; var denominator = args.length*(args.length - 1) / 2; var numerator = 0; for (i = 0; i < args.length; ++i) for (var j = i; j < args.length; ++j) numerator += Math.abs(args[i].getT() - args[j].getT()) * args[i].getC() * args[j].getC() * (1 - Math.abs((weights[i] - weights[j]) / (weights[i] + weights[j]))); var doc = numerator/denominator; return this._internalFusion(args, weights, doc); } else throw "Arrays are empty. Operation not allowed. \n"; } else throw "Different lengths of arrays. Operation not allowed. \n"; }; //=========== Internal Calculations ========== /** * Normalises r and s values according to n - maximal number of expected evidence * Important! Doesn't notify observers. */ CertainTrust.prototype._normaliseRS = function() { if ((this.r + this.s) > this.n) { var initR = this.r; this.r = (this.r * this.n) / (initR + this.s); this.s = (this.s * this.n) / (initR + this.s); } }; /** * Calculates t and c values based on existing r and s values * Important! Doesn't notify observers. */ CertainTrust.prototype._calculateRStoTC = function() { var rs = this.r + this.s; var nrs = this.n * rs; this.c = nrs / ((2 * this.weight * (this.n - this.r - this.s)) + nrs); if (this._almostEqual(this.c, 0)) this.t = 0.5; else this.t = this.r / rs; }; /** * Calculates r and s values based on existing c and t values * Important! Doesn't notify observers. */ CertainTrust.prototype._calculateTCtoRS = function() { if (this._almostEqual(this.c, 0)) { this.r = 0; this.s = 0; this.t = 0.5; } else { var c2w = this.c * 2 * this.weight; var c2wn = c2w * this.n; var cn = this.c * this.n; this.r = (c2wn * this.t) / (c2w + this.n - cn); this.s = (c2wn - (c2wn * this.t)) / (c2w + this.n - cn); } }; CertainTrust.prototype.clone = function() { var copy = new CertainTrust(this.getN()); 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; }; CertainTrust.prototype._isString = function (obj) { return typeof(obj) === 'string'; }; //=========== Observer ================= CertainTrust.prototype.notifyObservers = function(message) { for (var i = 0; i < this.observers.length; ++i) this.observers[i].update(this.observers[i], message); }; CertainTrust.prototype.addObserver = function(observer) { this.observers.push(observer); }; CertainTrust.prototype.deleteObserver = function(observer) { var idx = this.observers.indexOf(observer); if(idx !== -1) this.observers.splice(idx, 1); }; //=== shared functions for frontends === CertainTrust.prototype._insertElement = function(config, element) { var dom; if (config.domReturn === true) { return element; } else if (config.domParent !== undefined) { if (this._isString(config.domParent)) document.getElementById(config.domParent).appendChild(element); else config.domParent.appendChild(element); } else if (config.domBefore !== undefined) { if (this._isString(config.domBefore)) dom = document.getElementById(config.domBefore); else dom = config.domBefore; dom.parentNode.insertBefore(element, dom); } else { if (config.domAfter === undefined) { // the last script tag in DOM tree is the one creating this widget var scripts = document.getElementsByTagName('script'); dom = scripts[scripts.length - 1]; } else if (this._isString(config.domAfter)) dom = document.getElementById(config.domAfter); else dom = config.domAfter; dom.parentNode.insertBefore(element, dom.nextSibling); } return undefined; }; CertainTrust.prototype._getColor = function(certainty, trust, initf) { var resultp2 = ((1 - certainty) * initf); var result = (trust * certainty) + resultp2; var color; if (result < 0.5) { color = [ 255, Math.min(255, (255 * 2 * result)), 0 ]; } else { color = [ Math.min(255, ((2 - (2 * result)) * 255)), 255, 0 ]; } return color; }; CertainTrust.prototype._pointOnCircle = function(centerx, centery, pointgrade, radius) { var pointrad = ((360 + pointgrade) % 360) * ((2 * Math.PI) / 360); var chord = 2 * radius * Math.sin((pointrad / 2)); // height of our new point above the base-edge var y = Math.sqrt(2 * (Math.pow(chord, 2) * Math.pow(radius, 2) + Math.pow(radius, 4) + Math.pow(radius, 2) * Math.pow(chord, 2)) - (Math.pow(chord, 4) + 2 * Math.pow(radius, 4))) / (2 * radius); // distance to the cross-point of base-edge and height var a = Math.pow(radius, 2); var c = Math.pow(y, 2); // we do this to protect us from NaN cause by 1 - 1.00000004 var x = (a < c) ? 0 : Math.sqrt(a - c); var directions = new Array("NE", "SE", "SW", "NW"); var direction = 0; var alpharad = pointrad; while (alpharad > (0.5 * Math.PI)) { ++direction; alpharad -= (0.5 * Math.PI); } if (directions[direction] == "NE" || directions[direction] == "NW") x *= -1; if (directions[direction] == "SW" || directions[direction] == "NW") y *= -1; return new Array((centerx + x), (centery + y)); }; /* optional implementation of CertainTrust without R and S calculations */ var CertainTrustSimple = function() { this.weight = 2; this.observers = []; var offset = 0; this.name = ""; if (this._isString(arguments[0])) { this.name = arguments[0]; offset = 1; } if (arguments.length == 3 + offset || arguments.length == 4 + offset) { // CertainTrustSimple(t, c, f, doc) // doc is a 'private' parameter this.t = arguments[0 + offset]; this.c = arguments[1 + offset]; this.f = arguments[2 + offset]; this.doc = (arguments.length == 3 + offset) ? 0 : arguments[3 + offset]; if (this.f < 0 && this.f > 1) throw "f should lie within [0;1]. Entered f = " + this.f + "\n"; if (this.c < 0 && this.c > 1) throw "c should lie within [0;1]. Entered c = " + this.c + "\n"; if (this.t < 0 && this.t > 1) throw "t should lie within [0;1]. Entered t = " + this.t + "\n"; } else { this.c = 0; this.t = 0.5; this.f = 0.5; this.doc = 0; } }; CertainTrustSimple.prototype = new CertainTrust(1); CertainTrustSimple.prototype.constructor = CertainTrustSimple; CertainTrustSimple.prototype._operationAllowed = function() { return true; } CertainTrustSimple.prototype._calculateTCtoRS = function() { } CertainTrustSimple.prototype._calculateRStoTC = function() { } CertainTrustSimple.prototype._normaliseRS = function() { } CertainTrustSimple.prototype.setRS = undefined; CertainTrustSimple.prototype.addR = undefined; CertainTrustSimple.prototype.addS = undefined; CertainTrustSimple.prototype.setN = undefined; CertainTrustSimple.prototype.getR = undefined; CertainTrustSimple.prototype.getS = undefined; CertainTrustSimple.prototype.getN = undefined; CertainTrustSimple.prototype.clone = function() { var copy = new CertainTrustSimple(); copy.c = this.c; copy.t = this.t; copy.f = this.f; copy.doc = this.doc; return copy; }; /*Added by Debashis*/ /** * 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 - CertainTrustSimple object * @return - result of OR computation for this object and an argument. */ CertainTrust.prototype._singlesimpleOR = function(arg) { var c1 = this.getC(); var t1 = this.getT(); var f1 = this.getF(); var c2 = arg.getC(); var t2 = arg.getT(); var f2 = arg.getF(); var resT = 0.5, resF = 0.5, resC = 0; if (!this._operationAllowed(this, arg)) return undefined; resF = f1 + f2 - f1*f2; if (this._almostEqual(resF, 0)){ 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 (this._almostEqual(resC, 0)) resT = 0.5; else resT = (1/resC) * (c1*t1 + c2*t2 - c1*c2*t1*t2); resT = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); var result = new CertainTrustSimple(resT, resC, resF, this.n, 0); return result; }; /** * Computes OR 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.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. */ CertainTrustSimple.prototype.simpleOR = function() { var result = this.clone(); for (var i = 0; i < arguments.length; ++i) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singlesimpleOR(m); } return result; }; /** * Computes AND 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 AND computation for this object and an argument. */ CertainTrustSimple.prototype._singlesimpleAND = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; resF = f1*f2; if (this._almostEqual(resF, 1)){ //avoid division by 0 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 (this._almostEqual(resC, 0)) resT = 0.5; 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 = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrustSimple(resT, resC, resF); }; /** * Computes AND 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.AND(b, c, d) returns new CertainTrustSimple 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. */ CertainTrustSimple.prototype.simpleAND = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singlesimpleAND(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. */ CertainTrustSimple.prototype.simpleNOT = function() { var result = this.clone(); result.setTC(1 - this.getT(), this.getC()); result.setF(1 - this.getF()); result.setDoC(0); return result; }; CertainTrust.prototype.setName = function(newname) { this.name = newname; }; /** * 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. */ CertainTrust.prototype._singleCONSENSUS = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; var 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 = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrust(resT, resC, resF, this.n, 0); }; CertainTrust.prototype.CONSENSUS = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singleCONSENSUS(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. */ CertainTrust.prototype._singleDISCOUNTING = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; //resF = f1*f2; if (this._almostEqual(resF, 1)) //avoid division by 0 resC = t1*c1*c2; else resC = t1*c1*c2; if (this._almostEqual(resC, 0)) resT = t2; else if (this._almostEqual(resF, 1)) //avoid division by 0 resT = t2; else resT = t2; resT = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrust(resT, resC, resF, this.n, 0); }; CertainTrust.prototype.DISCOUNTING = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singleDISCOUNTING(m); } return result; }; /** * Computes CONSENSUS 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 - CertainTrustSimple object * @return - result of CONSENSUS computation for this object and an argument. */ CertainTrustSimple.prototype._singlesimpleCONSENSUS = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; var 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 = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrustSimple(resT, resC, resF); }; CertainTrustSimple.prototype.simpleCONSENSUS = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singlesimpleCONSENSUS(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 - CertainTrustSimple object * @return - result of DISCOUNTING computation for this object and an argument. */ CertainTrustSimple.prototype._singlesimpleDISCOUNTING = function(arg){ var c1 = this.getC(); var f1 = this.getF(); var t1 = this.getT(); var c2 = arg.getC(); var f2 = arg.getF(); var t2 = arg.getT(); var resC = 0, resT = 0.5, resF = 0.5; if (!this._operationAllowed(this, arg)) return undefined; //resF = f1*f2; if (this._almostEqual(resF, 1)) //avoid division by 0 resC = t1*c1*c2; else resC = t1*c1*c2; if (this._almostEqual(resC, 0)) resT = t2; else if (this._almostEqual(resF, 1)) //avoid division by 0 resT = t2; else resT = t2; resT = this._adjustValue(resT); resC = this._adjustValue(resC); resF = this._adjustValue(resF); return new CertainTrustSimple(resT, resC, resF, this.n, 0); }; CertainTrustSimple.prototype.simpleDISCOUNTING = function() { var result = this.clone(); for (var i = 0; i < arguments.length; i++) { var m = arguments[i]; if (!this._operationAllowed(this, m)) continue; result = result._singlesimpleDISCOUNTING(m); } return result; }; /** * 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 */ CertainTrustSimple.prototype._simpleinternalFusion = function(args, weights, doc) { var resC, resT, resF; var allOne = true; var allZero = true; var allWeightsZero = true; var atLeastOne1 = false; var arrLength = args.length; // set the flags about C and Weight values for (var i = 0; i < arrLength; ++i) if (args[i].getC() !== 1) { allOne = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (args[i].getC() !== 0) { allZero = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (weights[i] !== 0) { allWeightsZero = false; i = arrLength; } for (i = 0; i < arrLength; ++i) if (args[i].getC() === 1) { atLeastOne1 = true; i = arrLength; } //Calculate T and C // 1. all C's = 1 var numeratorT = 0, denominatorT = 0; if (allOne) { // set C resC = 1 * (1 - doc); // set T if (allWeightsZero) {// save some calculation time resT = 0; } else { // or use the function for (i = 0; i < arrLength; ++i) { numeratorT += weights[i] * args[i].getT(); denominatorT += weights[i]; } resT = numeratorT/denominatorT; } } else { if (atLeastOne1) throw "Illegal arguments. Either all C values must equal 1 or none of them. Operation not allowed\n"; else { // 2. Any other combination if (allWeightsZero) { // save some calculation time resT = 0; resC = 0; } else { // or use the function var numeratorC = 0, denominatorC = 0, mult; for (i = 0; i < arrLength; ++i) { mult = 1; for (var 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 { var numerator = 0, denominator = 0; for (i = 0; i < arrLength; ++i) { numerator += weights[i] * args[i].getF(); denominator += weights[i]; } resF = numerator/denominator; } var result = args[0].clone(); result.setTC(resT, resC); result.setF(resF); result.setDoC(doc); return result; }; /** * Performs weighted fusion for an array of CertainTrustSimple objects in correspondence with * an array of weights. Returns new CertainTrust object. * Requirements: N values of CertainTrustSimple 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 CertainTrustSimple objects * @param weights - an integer array of corresponding weights * @return - new CertainTrustSimple object */ CertainTrustSimple.prototype.simplewFusion = function(args, weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length !== 0) { for (var i = 1; i < args.length; ++i) if (!this._operationAllowed(args[0], args[i])) return undefined; return this._simpleinternalFusion(args, weights, 0); } else throw "Arrays are empty. Operation not allowed. \n"; } else throw "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 CertainTrust 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 */ CertainTrustSimple.prototype.simplecFusion = function(args, weights) { //arrays should be equal if (args.length == weights.length) { //and not empty if (args.length !== 0) { for (var i = 1; i < args.length; ++i) if (!this._operationAllowed(args[0], args[i])) return undefined; var denominator = args.length*(args.length - 1) / 2; var numerator = 0; for (i = 0; i < args.length; ++i) for (var j = i; j < args.length; ++j) numerator += Math.abs(args[i].getT() - args[j].getT()) * args[i].getC() * args[j].getC() * (1 - Math.abs((weights[i] - weights[j]) / (weights[i] + weights[j]))); var doc = numerator/denominator; return this._simpleinternalFusion(args, weights, doc); } else throw "Arrays are empty. Operation not allowed. \n"; } else throw "Different lengths of arrays. Operation not allowed. \n"; };