docs: private void computePhi(final Vec doc, int[] indexMap, double[] phiCols, int K, final Vec gamma_d, final Vec ELogTheta_d, final Vec ExpELogTheta_d)
      {
          //φ^k_dn ∝ exp{E[logθdk]+E[logβk,wdn ]}, k ∈ {1, . . . ,K}
          /*
           * we have the exp versions of each, and exp(log(x)+log(y)) = x y
           * so we can just use the doc product between the vectors per 
           * document to get the normalization constan Z
           * 
           * When we update γ we multiply by the word, so non presnet words 
           * have no impact. So we don't need ALL of the columbs from φ, but
           * only the columns for which we have non zero words. 
           */
  
          /*
           * normalized for each topic column (len K) of the words in this doc.
           * We only need to concern oursleves with the non zeros
           * 
           * Beacse we need to update several iterations, we will work with 
           * the inernal stricture dirrectly instead of using expensitve 
           * get/set on a Sparse Vector
           */
          
          int pos = 0;
          final SparseVector updateVec = new SparseVector(indexMap, phiCols, W, doc.nnz());
          for(IndexValue iv : doc)
          {
              int wordIndex = iv.getIndex();
              double sum = 0;
              for(int i = 0; i < ExpELogTheta_d.length(); i++)
                  sum += ExpELogTheta_d.get(i)*ExpELogBeta.get(i).get(wordIndex);
  
              indexMap[pos] = wordIndex;
              phiCols[pos] = iv.getValue()/(sum+1e-15);
              pos++;
          }
          //iterate till convergence or we hit arbitrary 100 limit (dont usually see more than 70)
          for(int iter = 0; iter < 100; iter++)
          {
              double meanAbsChange = 0;
              double gamma_d_sum = 0;
              //γtk = α+ w φ_twk n_tw
              for(int k = 0; k < K; k++)
              {
                  final double origGamma_dk = gamma_d.get(k);
                  double gamma_dtk = alpha;
  
                  gamma_dtk += ExpELogTheta_d.get(k) * updateVec.dot(ExpELogBeta.get(k));
                  gamma_d.set(k, gamma_dtk);
                  meanAbsChange += Math.abs(gamma_dtk-origGamma_dk);
                  gamma_d_sum += gamma_dtk;
              }
              
              //update Eq[log θtk] and our exponentated copy of it
              expandPsiMinusPsiSum(gamma_d, gamma_d_sum, ELogTheta_d);
              for(int i = 0; i < ELogTheta_d.length(); i++)
                  ExpELogTheta_d.set(i, FastMath.exp(ELogTheta_d.get(i)));
              
              //update our column norm norms 
              int indx = 0;
              for(IndexValue iv : doc)
              {
                  int wordIndex = iv.getIndex();
                  double sum = 0;
                  for(int i = 0; i < ExpELogTheta_d.length(); i++)
                      sum += ExpELogTheta_d.get(i)*ExpELogBeta.get(i).get(wordIndex);
                  phiCols[indx] = iv.getValue() / (sum + 1e-15);
                  indx++;
              }
              
              /*
               * //original papser uses a tighter bound, but our approximation
               * isn't that good - and this seems to work well enough
               * 0.01 even seems to work, but need to try that more before 
               * switching
               */
              if(meanAbsChange < 0.001*K)
                  break;
          }
      }