private Matrix getTObs(Instances data) throws Exception {
    
    int p = m_numAttributes; // number of columns
    
    // matrix of complete-data sufficient statistics for observed values
    Matrix t = new Matrix(p+1, p+1);
    
    // initialize T for observed data (T_obs)
    int currentPatternStart = 0;
    while (currentPatternStart < data.numInstances()) {
      // number of instances in current missingness pattern is held in 1st attribute
      int numInCurrentPattern = (int) data.instance(currentPatternStart).value(0);
      t.set(0, 0, t.get(0,0) + numInCurrentPattern);
      for (int i = 1; i < p + 1; i++) {
        // if current column is not missing in this pattern
        if (!data.instance(currentPatternStart).isMissing(i)) {
          // add values in this column for this pattern
          for (int k = 0; k < numInCurrentPattern; k++) {
            t.set(0, i, t.get(0, i) + data.instance(currentPatternStart + k).value(i));
          }
          // iterate through columns to add appropriate squares and crossproducts
          for (int j = i; j < p + 1; j++) {
            // if this column is also not missing in the current missingness pattern
            if (!data.instance(currentPatternStart).isMissing(j)) {
              for (int k = 0; k < numInCurrentPattern; k++) {
                t.set(i, j, t.get(i, j) + 
                      data.instance(currentPatternStart + k).value(i) * 
                      data.instance(currentPatternStart + k).value(j));
              } // end iterating through instances in currrent missingness pattern
            }
          } // end iterating through column indices (inner loop) 
        }
      } // end iterating through column indices (outer loop)
      
      // move counter to start of next missingness pattern (or end of dataset)
      currentPatternStart += numInCurrentPattern;
    } // end iterating through missingness patterns
    
    // copy to symmetric lower triangular portion
    for (int i = 0; i < p + 1; i++) {
      for (int j = 1; j < p + 1; j++) {
        t.set(j, i, t.get(i, j));
      }
    }
    
    return t;
  }