/**
   * Calculate similarity between two items, based on the global base SVD.
   *
   * @param idx1 The first item's ID.
   * @param idx2 The second item's ID.
   * @return The similarity value between two items idx1 and idx2.
   */
  private static double getItemSimilarity(int idx1, int idx2) {
    double sim;
    if (idx1 <= idx2) {
      sim = itemSimilarity.getValue(idx1, idx2);
    } else {
      sim = itemSimilarity.getValue(idx2, idx1);
    }

    if (sim == 0.0) {
      SparseVector i_vec = baseline.getV().getColRef(idx1);
      SparseVector j_vec = baseline.getV().getColRef(idx2);

      sim =
          1 - 2.0 / Math.PI * Math.acos(i_vec.innerProduct(j_vec) / (i_vec.norm() * j_vec.norm()));

      if (Double.isNaN(sim)) {
        sim = 0.0;
      }

      if (idx1 <= idx2) {
        itemSimilarity.setValue(idx1, idx2, sim);
      } else {
        itemSimilarity.setValue(idx2, idx1, sim);
      }
    }

    return sim;
  }
  /**
   * Calculate similarity between two users, based on the global base SVD.
   *
   * @param idx1 The first user's ID.
   * @param idx2 The second user's ID.
   * @return The similarity value between two users idx1 and idx2.
   */
  private static double getUserSimilarity(int idx1, int idx2) {
    double sim;
    if (idx1 <= idx2) {
      sim = userSimilarity.getValue(idx1, idx2);
    } else {
      sim = userSimilarity.getValue(idx2, idx1);
    }

    if (sim == 0.0) {
      SparseVector u_vec = baseline.getU().getRowRef(idx1);
      SparseVector v_vec = baseline.getU().getRowRef(idx2);

      sim =
          1 - 2.0 / Math.PI * Math.acos(u_vec.innerProduct(v_vec) / (u_vec.norm() * v_vec.norm()));

      if (Double.isNaN(sim)) {
        sim = 0.0;
      }

      if (idx1 <= idx2) {
        userSimilarity.setValue(idx1, idx2, sim);
      } else {
        userSimilarity.setValue(idx2, idx1, sim);
      }
    }

    return sim;
  }