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;
  }
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)
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 .