+
+/*
+ Make sure the dependent variable is at the last column, and that
+ only variables in the model are in the covariance matrix.
+ */
+static struct design_matrix *
+rearrange_covariance_matrix (const struct covariance_matrix *cm, pspp_linreg_cache *c)
+{
+ const struct variable **model_vars;
+ struct design_matrix *cov;
+ struct design_matrix *result;
+ size_t *permutation;
+ size_t i;
+ size_t j;
+ size_t k;
+ size_t n_coeffs = 0;
+
+ assert (cm != NULL);
+ cov = covariance_to_design (cm);
+ assert (cov != NULL);
+ assert (c != NULL);
+ assert (cov->m->size1 > 0);
+ assert (cov->m->size2 == cov->m->size1);
+ model_vars = xnmalloc (1 + c->n_indeps, sizeof (*model_vars));
+
+ /*
+ Put the model variables in the right order in MODEL_VARS.
+ Count the number of coefficients.
+ */
+ for (i = 0; i < c->n_indeps; i++)
+ {
+ model_vars[i] = c->indep_vars[i];
+ }
+ model_vars[i] = c->depvar;
+ result = covariance_matrix_create (1 + c->n_indeps, model_vars);
+ permutation = xnmalloc (design_matrix_get_n_cols (result), sizeof (*permutation));
+
+ for (j = 0; j < cov->m->size2; j++)
+ {
+ k = 0;
+ while (k < result->m->size2)
+ {
+ if (design_matrix_col_to_var (cov, j) == design_matrix_col_to_var (result, k))
+ {
+ permutation[k] = j;
+ }
+ k++;
+ }
+ }
+ for (i = 0; i < result->m->size1; i++)
+ for (j = 0; j < result->m->size2; j++)
+ {
+ gsl_matrix_set (result->m, i, j, gsl_matrix_get (cov->m, permutation[i], permutation[j]));
+ }
+ free (permutation);
+ free (model_vars);
+ return result;
+}
+/*
+ Estimate the model parameters from the covariance matrix only. This
+ method uses less memory than PSPP_LINREG, which requires the entire
+ data set to be stored in memory.
+
+ The function assumes FULL_COV may contain columns corresponding to
+ variables that are not in the model. It fixes this in
+ REARRANG_COVARIANCE_MATRIX. This allows the caller to compute a
+ large covariance matrix once before, then pass it to this without
+ having to alter it. The problem is that this means the caller must
+ set CACHE->N_COEFFS.
+*/
+void
+pspp_linreg_with_cov (const struct covariance_matrix *full_cov,
+ pspp_linreg_cache * cache)
+{
+ struct design_matrix *cov;
+
+ assert (full_cov != NULL);
+ assert (cache != NULL);
+
+ cov = rearrange_covariance_matrix (full_cov, cache);
+ cache_init (cache);
+ reg_sweep (cov->m);
+ post_sweep_computations (cache, cov, cov->m);
+ design_matrix_destroy (cov);
+}
+
+double pspp_linreg_mse (const pspp_linreg_cache *c)
+{
+ assert (c != NULL);
+ return (c->sse / c->dfe);
+}