/*----------------------------------------------------- Functions for predicting user's prefernce based on the memeory based models defined in Breese et al. - Guy Lebanon, July 2003. ------------------------------------------------------*/ #include #include #include #include "mex.h" #define EPS 0.00001 /*------------------------------------------------- a structure that represents a (single) vote on a specific item by a specific user. --------------------------------------------------*/ typedef struct vote { int itemID; int value; } vote; typedef struct user { int numItems; int defaultVote; int numVotes; vote* votes; } user; /*------------------------------------------------- Computes the average vote for a specific user. If defaultVote>0, the unvoted items get a vote of defaultVote. -------------------------------------------------*/ double AverageVote(const user u) { int i; double res=0; for (i=0;i0) return (res+u.defaultVote*(u.numItems-u.numVotes)) /( (double)u.numItems); else return res / ( (double)u.numVotes); } /*------------------------------------------------- Computes the sum of squared votes for a specific user. If defaultVote>0, the unvoted items get a vote of defaultVote. -------------------------------------------------*/ double SumSquaresVote(const user u) { int i; double res=0; for (i=0;i0) return res+pow(u.defaultVote,2)*(u.numItems-u.numVotes); else return res; } /*------------------------------------------------- Computes the variance vote for a specific user. If defaultVote>0, the unvoted items get a vote if defaultVote. Note: This is non-normalized (not divided by the number of votes). -------------------------------------------------*/ double VarianceVote(const user u) { int i; double avg=AverageVote(u); double res=0; for (i=0;i0) return res + pow(u.defaultVote-avg,2) * (u.numItems-u.numVotes); else return res; } /*--------------------------------------------------- Computes the Pearson's correlation between two users (equation (2) at Breese et al.). If defaultVote>0, the unvoted items get a vote defaultVote. IMPORTANT: The votes of users u,v are assumed to be sorted according to itemID. -----------------------------------------------------*/ double Correlation(const user u, const user v) { double avg1,avg2,cov=0,var1=0,var2=0; int i=0,j=0,currID1,currID2,intersectionSize=0,nonUnionSize; avg1=AverageVote(u); avg2=AverageVote(v); var1=VarianceVote(u);var2=VarianceVote(v); while (1) { if (i>=u.numVotes || j>=v.numVotes) break; currID1=u.votes[i].itemID; currID2=v.votes[j].itemID; if (currID10) cov += (u.votes[i].value-avg1)*(v.defaultVote-avg2); i++; } else if (currID1>currID2) { if (u.defaultVote>0) cov += (u.defaultVote-avg1)*(v.votes[j].value-avg2); j++; } else { /* The two items are equal */ cov += (u.votes[i].value-avg1)*(v.votes[j].value-avg2); i++; j++; intersectionSize++; } } if (u.defaultVote>0) {/* add default vote to unvoted items*/ if (i0, the unvoted items get a vote defaultVote. IMPORTANT: The votes in user1,user2 are assumed to be sorted according to itemID. ---------------------------------------------------------------*/ double VectorSimilarity(const user u, const user v) { double normU,normV,dotProd=0; int i=0,j=0,currID1,currID2,intersectionSize=0,nonUnionSize; normU=sqrt(SumSquaresVote(u));normV=sqrt(SumSquaresVote(v)); while (1) { if (i>=u.numVotes || j>=v.numVotes) break; currID1=u.votes[i].itemID; currID2=v.votes[j].itemID; if (currID10) dotProd += u.votes[i].value * v.defaultVote; i++; } else if (currID1>currID2) { if (u.defaultVote>0) dotProd += v.votes[j].value * u.defaultVote; j++; } else { /* The two items are equal */ dotProd += u.votes[i].value * v.votes[j].value; i++;j++; intersectionSize++; } } if (u.defaultVote>0) {/* add default vote to unvoted items*/ if (i= 0) return pow(weight,rho); else return - fabs(pow(weight,rho)); } /*------------------------------------------------------------ Computes memory based similarity of one user (u) to several (vsLen) other users (stored in vs). The result will be stored in res, which need to be pre-allocated before function call. -------------------------------------------------------------*/ void computeSimilarityOne2Many(const user u, const user* vs, int vsLen, int method, double* res) { int i; for (i=0;i0) and the total number of distinct items. -----------------------------------------------------------------------*/ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int usSz, vsSz,i,j,simMethod; user* us, *vs; double* res, *matlabVotes; /* Check number of input and output arguments */ if (nrhs != 5) mexErrMsgTxt("Five input arguments required"); if (nlhs != 1) mexErrMsgTxt("One output argument required"); if ( ! mxIsCell(prhs[0]) || ! mxIsCell(prhs[1])) mexErrMsgTxt("First two input arguments have to be cell arrays"); usSz = mxGetM(prhs[0]); vsSz = mxGetM(prhs[1]); simMethod = mxGetScalar(prhs[2]); /* read the two users into struct arrays */ us = mxCalloc(usSz,sizeof(user)); for (i=0;i