code: public static void mult(DMatrixSparseCSC A, DMatrixSparseCSC B, DMatrixSparseCSC C,
                              @Nullable IGrowArray gw, @Nullable DGrowArray gx )
      {
          double []x = adjust(gx, A.numRows);
          int []w = adjust(gw, A.numRows, A.numRows);
  
          C.growMaxLength(A.nz_length+B.nz_length,false);
          C.indicesSorted = false;
          C.nz_length = 0;
  
          // C(i,j) = sum_k A(i,k) * B(k,j)
          int idx0 = B.col_idx[0];
          for (int bj = 1; bj <= B.numCols; bj++) {
              int colB = bj-1;
              int idx1 = B.col_idx[bj];
              C.col_idx[bj] = C.nz_length;
  
              if( idx0 == idx1 ) {
                  continue;
              }
  
              // C(:,j) = sum_k A(:,k)*B(k,j)
              for (int bi = idx0; bi < idx1; bi++) {
                  int rowB = B.nz_rows[bi];
                  double valB = B.nz_values[bi];  // B(k,j)  k=rowB j=colB
  
                  multAddColA(A,rowB,valB,C,colB+1,x,w);
              }
  
              // take the values in the dense vector 'x' and put them into 'C'
              int idxC0 = C.col_idx[colB];
              int idxC1 = C.col_idx[colB+1];
  
              for (int i = idxC0; i < idxC1; i++) {
                  C.nz_values[i] = x[C.nz_rows[i]];
              }
  
              idx0 = idx1;
          }
  
      }
docs: Performs matrix multiplication.  C = A*B
  
  @param A Matrix
  @param B Matrix
  @param C Storage for results.  Data length is increased if increased if insufficient.
  @param gw (Optional) Storage for internal workspace.  Can be null.
  @param gx (Optional) Storage for internal workspace.  Can be null.