+ return cm_to_gsl (cov);
+}
+
+static gsl_matrix *
+covariance_calculate_single_pass_unnormalized (struct covariance *cov)
+{
+ size_t i, j;
+
+ for (i = 0 ; i < cov->dim; ++i)
+ {
+ for (j = 0 ; j < cov->dim; ++j)
+ {
+ double *x = gsl_matrix_ptr (cov->moments[MOMENT_VARIANCE], i, j);
+ *x -= pow2 (gsl_matrix_get (cov->moments[MOMENT_MEAN], i, j))
+ / gsl_matrix_get (cov->moments[MOMENT_NONE], i, j);
+ }
+ }
+ for ( j = 0 ; j < cov->dim - 1; ++j)
+ {
+ for (i = j + 1 ; i < cov->dim; ++i)
+ {
+ double *x = &cov->cm [cm_idx (cov, i, j)];
+
+ *x -=
+ gsl_matrix_get (cov->moments[MOMENT_MEAN], i, j)
+ *
+ gsl_matrix_get (cov->moments[MOMENT_MEAN], j, i)
+ / gsl_matrix_get (cov->moments[MOMENT_NONE], i, j);
+ }
+ }
+
+ return cm_to_gsl (cov);
+}
+
+
+/* Return a pointer to gsl_matrix containing the pairwise covariances. The
+ caller owns the returned matrix and must free it when it is no longer
+ needed.
+
+ Call this function only after all data have been accumulated. */
+gsl_matrix *
+covariance_calculate_unnormalized (struct covariance *cov)
+{
+ if ( cov->state <= 0 )
+ return NULL;
+
+ switch (cov->passes)
+ {
+ case 1:
+ return covariance_calculate_single_pass_unnormalized (cov);
+ break;
+ case 2:
+ return covariance_calculate_double_pass_unnormalized (cov);
+ break;
+ default:
+ NOT_REACHED ();
+ }
+}
+
+/* Function to access the categoricals used by COV
+ The return value is owned by the COV
+*/
+const struct categoricals *
+covariance_get_categoricals (const struct covariance *cov)
+{
+ return cov->categoricals;
+}