package prea.recommender.llorma;

import prea.data.structure.SparseMatrix;
import prea.data.structure.SparseVector;

/**
 * TODO: Insert description here. (generated by joonseok)
 */
public class SingletonLLORMAUpdater extends Thread {
	private SparseMatrix localUserFeature;
	private SparseMatrix localItemFeature;
	private int rank;
	private int userCount;
	private SparseMatrix rateMatrix;
	private SparseMatrix currentPrediction;
	private double[][] weightSum;
	private double learningRate;
	private double regularizer;
	private SparseVector w;
	private SparseVector v;
	
	public SingletonLLORMAUpdater(SparseMatrix luf, SparseMatrix lif, SparseMatrix rm,
			SparseMatrix cp, double[][] ws, double lr, double r, SparseVector w0, SparseVector v0) {
		localUserFeature = luf;
		localItemFeature = lif;
		userCount = (localUserFeature.length())[0];
		rank = (localUserFeature.length())[1];
		rateMatrix = rm;
		currentPrediction = cp;
		weightSum = ws;
		learningRate = lr;
		regularizer = r;
		w = w0;
		v = v0;
	}
	
	public SparseMatrix getUserFeature() {
		return localUserFeature;
	}
	
	public SparseMatrix getItemFeature() {
		return localItemFeature;
	}
	
	@Override
	public void run() {
		for (int u = 1; u <= userCount; u++) {
			SparseVector items = rateMatrix.getRowRef(u);
			int[] itemIndexList = items.indexList();
			
			if (itemIndexList != null) {
				for (int i : itemIndexList) {
					// current estimation:
					double RuiEst = currentPrediction.getValue(u, i);
					double RuiReal = rateMatrix.getValue(u, i);
					double err = RuiReal - RuiEst;
					
					// parameter update:
					double weight = w.getValue(u) * v.getValue(i) / weightSum[u][i];
					
					for (int r = 0; r < rank; r++) {
						double Fus = localUserFeature.getValue(u, r);
						double Gis = localItemFeature.getValue(r, i);
						
						localUserFeature.setValue(u, r, Fus + learningRate*(err*Gis*weight - regularizer*Fus));
						if(Double.isNaN(Fus + learningRate*(err*Gis*weight - regularizer*Fus))) {
							System.out.println("a");
						}
						localItemFeature.setValue(r, i, Gis + learningRate*(err*Fus*weight - regularizer*Gis));
						if(Double.isNaN(Gis + learningRate*(err*Fus*weight - regularizer*Gis))) {
							System.out.println("b");
						}
					}
				}
			}
		}
	}
}
