module dregs.algorithms.yzlm; import std.math; import std.stdio; public import dregs.core; class Yzlm : ReputationAlgorithm { double beta; double convergenceRequirement; double errorMin; // uint[] userLinks; // commented out because for now it // has a constant value for all users double[] weightSum; double[] oldReputationObject; double objectReputationUpdate(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { double diff = 0; double[] temp = oldReputationObject; // Original version had: // // oldReputationObject[] = reputationObject[] // // This version is an attempt to save effort // by just switching round the memory the two // arrays are pointing at -- not sure if it // actually does what I'm expecting it to. // Doesn't seem to improve speed. :-( oldReputationObject = reputationObject; reputationObject = temp; reputationObject[] = 0; weightSum[] = 0; foreach(Rating r; ratings) { reputationObject[r.object] += reputationUser[r.user] * r.value; weightSum[r.object] += reputationUser[r.user]; } foreach(uint object, ref double r; reputationObject) { r /= (weightSum[object]>0) ? weightSum[object] : 1; diff += pow( (r - oldReputationObject[object]), 2); } return sqrt(diff); } void userReputationUpdate(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { reputationUser[] = 0; foreach(Rating r; ratings) reputationUser[r.user] += pow( (r.value - reputationObject[r.object]), 2); foreach(uint user, ref double r; reputationUser) { //if(userLinks[user]>0) r = pow( (r/reputationObject.length/*userLinks[user]*/) + errorMin, -beta); } } void opCall(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { // userLinks.length = reputationUser.length; // userLinks[] = 0; weightSum.length = reputationObject.length; oldReputationObject.length = reputationObject.length; // foreach(Rating r; ratings) // userLinks[r.user]++; double diff; uint iterations=0; do { userReputationUpdate(ratings, reputationUser, reputationObject); diff = objectReputationUpdate(ratings, reputationUser, reputationObject); ++iterations; } while(diff > convergenceRequirement); writefln("Exited in %u iterations with diff = %g < %g",iterations,diff,convergenceRequirement); } this() {} this(double b, double c, double e) { beta = b; convergenceRequirement = c; errorMin = e; assert(beta>=0); assert(convergenceRequirement>0); assert(errorMin>=0); } this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject, double b, double c, double e) { this(b,c,e); opCall(ratings, reputationUser, reputationObject); } }