app/oryx-app-common/src/main/java/com/cloudera/oryx/app/als/ALSUtils.java
public static float[] computeUpdatedXu(Solver solver,
                                         double value,
                                         float[] Xu,
                                         float[] Yi,
                                         boolean implicit) {
    if (Yi == null) {
      return null;
    }

    boolean noXu = Xu == null;
    double Qui = noXu ? 0.0 : VectorMath.dot(Xu, Yi);
    // Qui' is the target, new value of Qui
    // 0.5 reflects a "don't know" state
    double targetQui = computeTargetQui(implicit, value, noXu ? 0.5 : Qui);
    if (Double.isNaN(targetQui)) {
      return null;
    }

    double dQui = targetQui - Qui;
    double[] dQuiYi = new double[Yi.length];
    for (int i = 0; i < dQuiYi.length; i++) {
      dQuiYi[i] = Yi[i] * dQui;
    }
    double[] dXu = solver.solveDToD(dQuiYi);

    float[] newXu = noXu ? new float[dXu.length] : Xu.clone();
    for (int i = 0; i < newXu.length; i++) {
      newXu[i] += dXu[i];
    }
    return newXu;
  }
public static float[] computeUpdatedXu(Solver solver,
                                         double value,
                                         float[] Xu,
                                         float[] Yi,
                                         boolean implicit) {
    if (Yi == null) {
      return null;
    }

    boolean noXu = Xu == null;
    double Qui = noXu ? 0.0 : VectorMath.dot(Xu, Yi);
    // Qui' is the target, new value of Qui
    // 0.5 reflects a "don't know" state
    double targetQui = computeTargetQui(implicit, value, noXu ? 0.5 : Qui);
    if (Double.isNaN(targetQui)) {
      return null;
    }

    double dQui = targetQui - Qui;
    double[] dQuiYi = new double[Yi.length];
    for (int i = 0; i < dQuiYi.length; i++) {
      dQuiYi[i] = Yi[i] * dQui;
    }
    double[] dXu = solver.solveDToD(dQuiYi);

    float[] newXu = noXu ? new float[dXu.length] : Xu.clone();
    for (int i = 0; i < newXu.length; i++) {
      newXu[i] += dXu[i];
    }
    return newXu;
  }
Computes how a user vector Xu changes in response to interaction with an item vector Yi.
This can also be used to compute how an item vector changes in response to a user interaction,
even though the code naming follows the former convention.

@param solver solver helping solve for Xu in Qu*Y = Xu * (Yt * Y)
@param value strength of interaction
@param Xu current user vector (null if no existing user vector)
@param Yi current item vector
@param implicit whether the model is implicit feedback
@return new user vector Xu, or {@code null} if no update should be made (i.e. there was no
item vector; the update would push the new Qui farther out of range)