}
// Here, we are using userFeatures, which is a row of X, as if it were a column of X'.
// This is multiplied on the left by (X'*X)^-1. That's our left-inverse of X or at least the one
// column we need. Which is what the new data point is multiplied on the left by. The result is a column;
// we scale to complete the multiplication of the fold-in and add it in.
Solver xtxSolver = generation.getXTXSolver();
double[] itemFoldIn = xtxSolver == null ? null : xtxSolver.solveFToD(userFeatures);
// Same, but reversed. Multiply itemFeatures, which is a row of Y, on the right by (Y'*Y)^-1.
// This is the right-inverse for Y', or at least the row we need. Because of the symmetries we can use
// the same method above to carry out the multiply; the result is conceptually a row vector.
// The result is scaled and added in.
Solver ytySolver = generation.getYTYSolver();
double[] userFoldIn = ytySolver == null ? null : ytySolver.solveFToD(itemFeatures);
if (itemFoldIn != null) {
if (SimpleVectorMath.norm(userFoldIn) > BIG_FOLDIN_THRESHOLD) {
log.warn("Item fold in vector is large; reduce -Dmodel.features?");
}