/// <param name="data">data</param>
/// <param name="W">W</param>
/// <param name="H">H</param>
protected void Optimize(IBooleanMatrix data, Matrix W, Matrix H)
{
Matrix HH = new Matrix(num_factors, num_factors);
Matrix HC_minus_IH = new Matrix(num_factors, num_factors);
double[] HCp = new double[num_factors];
cern.colt.matrix.DoubleMatrix2D m=new cern.colt.matrix.impl.DenseDoubleMatrix2D(num_factors,num_factors);
cern.colt.matrix.DoubleMatrix2D m_inv;
// TODO speed up using more parts of that library
// source code comments are in terms of computing the user factors
// works the same with users and items exchanged
// (1) create HH in O(f^2|Items|)
// HH is symmetric
for (int f_1 = 0; f_1 < num_factors; f_1++)
for (int f_2 = 0; f_2 < num_factors; f_2++)
{
double d = 0;
for (int i = 0; i < H.dim1; i++)
d += H.getLocation(i, f_1) * H.getLocation(i, f_2);
HH.setLocation(f_1, f_2,d);
}
// (2) optimize all U
// HC_minus_IH is symmetric
for (int u = 0; u < W.dim1; u++)
{
List<Integer> row = data.GetEntriesByRow(u);
// create HC_minus_IH in O(f^2|S_u|)
for (int f_1 = 0; f_1 < num_factors; f_1++)
for (int f_2 = 0; f_2 < num_factors; f_2++)
{
double d = 0;
for(int i1=0;i1<row.size();i1++){
int i=row.get(i1);
d += H.getLocation(i, f_1) * H.getLocation(i, f_2) * c_pos;
}
HC_minus_IH.setLocation(f_1, f_2, d);
}
// create HCp in O(f|S_u|)
for (int f = 0; f < num_factors; f++)
{
double d = 0;
for(int i1=0;i1<row.size();i1++){
int i=row.get(i1);
d += H.getLocation(i, f) * (1 + c_pos);
}
HCp[f] = d;
}
// create m = HH + HC_minus_IH + reg*I
// m is symmetric
// the inverse m_inv is symmetric
cern.colt.matrix.linalg.Algebra a=new cern.colt.matrix.linalg.Algebra();
for (int f_1 = 0; f_1 < num_factors; f_1++)
for (int f_2 = 0; f_2 < num_factors; f_2++)
{
double d = HH.getLocation(f_1, f_2) + HC_minus_IH.getLocation(f_1, f_2);
if (f_1 == f_2)
d += regularization;
m.set(f_1, f_2, d);
}
m_inv = a.inverse(m);