#include #include #include #include using namespace std; using namespace boost; namespace fric { class Rating { private: size_t _user; size_t _object; double _value; public: Rating() {} Rating(size_t u, size_t o, double v) { _user = u; _object = o; _value = v; } const size_t &user() { return _user; } const size_t &object() { return _object; } const double &value() { return _value; } }; class ReputationAlgorithm { virtual size_t reputation(vector &reputationUser, vector &reputationObject, vector &ratings) { return 0; } virtual size_t addRating(vector &reputationUser, vector &reputationObject, vector &ratings, Rating r) { return 0; } }; namespace algorithm { class AvgWeighted : ReputationAlgorithm { protected: vector weightSum; public: virtual size_t reputation(vector &reputationUser, vector &reputationObject, vector &ratings) { weightSum.assign(reputationObject.size(),0.0); reputationObject.assign(reputationObject.size(),0.0); BOOST_FOREACH(Rating &r, ratings) { reputationObject.at(r.object()) += reputationUser.at(r.user()) * r.value(); weightSum.at(r.object()) += reputationUser.at(r.user()); } for(size_t o=0;o!=reputationObject.size();++o) reputationObject.at(o) /= (weightSum.at(o)>0) ? weightSum.at(o) : 1; return 0; } }; class AvgArithmetic : AvgWeighted { public: virtual size_t reputation(vector &reputationUser, vector &reputationObject, vector &ratings) { reputationUser.assign(reputationUser.size(),1.0); return AvgWeighted::reputation(reputationUser,reputationObject,ratings); } }; class Yzlm : AvgWeighted { private: double _beta; double _convergence; double _errorMin; protected: vector oldReputationObject; vector userLinks; double objectReputationUpdate(vector &reputationUser, vector &reputationObject, vector &ratings) { double diff = 0.0; oldReputationObject.assign(reputationObject.begin(), reputationObject.end()); AvgWeighted::reputation(reputationUser, reputationObject, ratings); for(size_t o=0;o!=reputationObject.size();++o) { double aux = reputationObject.at(o) - oldReputationObject.at(o); diff += aux*aux; } return sqrt(diff); } void userReputationUpdate(vector &reputationUser, vector &reputationObject, vector &ratings) { reputationUser.assign(reputationUser.size(),0.0); BOOST_FOREACH(Rating &r, ratings) { double aux = r.value() - reputationObject.at(r.object()); reputationUser.at(r.user()) += aux*aux; } for(size_t u=0;u!=reputationUser.size();++u) { if(userLinks.at(u)!=0) reputationUser.at(u) = pow( (reputationUser.at(u)/userLinks.at(u)) + errorMin(), -beta() ); } } public: void init(double b, double c, double e) { _beta = b; _convergence = c; _errorMin = e; } const double &beta() { return _beta; } const double &convergence() { return _convergence; } const double &errorMin() { return _errorMin; } virtual size_t reputation(vector &reputationUser, vector &reputationObject, vector &ratings) { double diff; size_t iterations = 0; userLinks.assign(reputationUser.size(),0); oldReputationObject.resize(reputationObject.size()); BOOST_FOREACH(Rating &r, ratings) userLinks.at(r.user())++; do { userReputationUpdate(reputationUser,reputationObject,ratings); diff = objectReputationUpdate(reputationUser,reputationObject,ratings); ++iterations; } while(diff > convergence()); cout << "Exited in " << iterations << " iterations with diff = " << diff << endl; return iterations; } Yzlm(double b, double c, double e) { init(b,c,e); } }; } } using namespace fric; int main() { vector reputationUser, reputationObject; vector userError, objectQuality; vector ratings; mt19937 rng; algorithm::AvgArithmetic aa; algorithm::Yzlm yzlm(0.8,1e-12,1e-36); reputationUser.resize(100); reputationObject.resize(1); rng.seed(1001); for(size_t u=0;u!=reputationUser.size();++u) ratings.push_back(Rating(u,0,u+1)); aa.reputation(reputationUser,reputationObject,ratings); BOOST_FOREACH(double r, reputationObject) cout << r << endl; objectQuality.resize(1000); userError.resize(1000); reputationObject.resize(objectQuality.size()); reputationUser.resize(userError.size()); ratings.reserve(objectQuality.size() * userError.size()); size_t iterTotal = 0; for(size_t i=0;i!=100;++i) { BOOST_FOREACH(double &Q, objectQuality) Q = uniform_real (0.0, 10.0) (rng); BOOST_FOREACH(double &err, userError) err = uniform_real (0.0, 1.0) (rng); ratings.resize(0); for(size_t o=0;o!=objectQuality.size();++o) { for(size_t u=0;u!=userError.size();++u) { ratings.push_back( Rating(u, o, uniform_real (objectQuality.at(o)-userError.at(u), objectQuality.at(o)+userError.at(u)) (rng) ) ); } } cout << "We now have " << ratings.size() << " ratings, with capacity for " << ratings.capacity() << endl; aa.reputation(reputationUser, reputationObject, ratings); iterTotal += yzlm.reputation(reputationUser, reputationObject, ratings); double deltaQ = 0.0; for(size_t o=0;o!=objectQuality.size();++o) { double aux = reputationObject.at(o) - objectQuality.at(o); deltaQ += aux*aux; } deltaQ = sqrt(deltaQ/objectQuality.size()); cout << "[" << i << "] Error in quality estimate: " << deltaQ << endl; } cout << endl; cout << "Total iterations: " << iterTotal << endl; return 0; }