FACTOR: Do not try to run an analysis if no matrix is present
[pspp] / src / language / stats / factor.c
index 3043fced29cb69d8e5cd5215475f5820817e6dfe..49bc8a4d67f5334fa4af3737edd99b1d4c368acd 100644 (file)
@@ -266,10 +266,6 @@ idata_free (struct idata *id)
   gsl_vector_free (id->msr);
   gsl_vector_free (id->eval);
   gsl_matrix_free (id->evec);
-  if (id->mm.cov != NULL)
-    gsl_matrix_free (id->mm.cov);
-  if (id->mm.corr != NULL)
-    gsl_matrix_free (CONST_CAST (gsl_matrix *, id->mm.corr));
 
   free (id);
 }
@@ -1009,7 +1005,7 @@ iterate_factor_matrix (const gsl_matrix *r, gsl_vector *communalities, gsl_matri
 
 static bool run_factor (struct dataset *ds, const struct cmd_factor *factor);
 
-static void do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata);
+static bool do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata);
 
 
 
@@ -1057,6 +1053,7 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
     }
   else if (lex_match_id (lexer, "MATRIX"))
     {
+      lex_match (lexer, T_EQUALS);
       if (! lex_force_match_id (lexer, "IN"))
        goto error;
       if (!lex_force_match (lexer, T_LPAREN))
@@ -1380,11 +1377,10 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
                {
                  factor.print |= PRINT_CORRELATION;
                }
-#if FACTOR_FULLY_IMPLEMENTED
              else if (lex_match_id (lexer, "COVARIANCE"))
                {
+                 factor.print |= PRINT_COVARIANCE;
                }
-#endif
              else if (lex_match_id (lexer, "ROTATION"))
                {
                  factor.print |= PRINT_ROTATION;
@@ -1480,7 +1476,9 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        {
          do_factor_by_matrix (&factor, id);
 
+         gsl_matrix_free (id->mm.corr);
          id->mm.corr = NULL;
+         gsl_matrix_free (id->mm.cov);
          id->mm.cov = NULL;
        }
 
@@ -1556,14 +1554,14 @@ the_communality (const gsl_matrix *evec, const gsl_vector *eval, int n, int n_fa
 
 /* Return the communality of variable N, calculated to N_FACTORS */
 static double
-communality (struct idata *idata, int n, int n_factors)
+communality (const struct idata *idata, int n, int n_factors)
 {
   return the_communality (idata->evec, idata->eval, n, n_factors);
 }
 
 
 static void
-show_scree (const struct cmd_factor *f, struct idata *idata)
+show_scree (const struct cmd_factor *f, const struct idata *idata)
 {
   struct scree *s;
   const char *label ;
@@ -1648,7 +1646,7 @@ show_communalities (const struct cmd_factor * factor,
 
 
 static void
-show_factor_matrix (const struct cmd_factor *factor, struct idata *idata, const char *title, const gsl_matrix *fm)
+show_factor_matrix (const struct cmd_factor *factor, const struct idata *idata, const char *title, const gsl_matrix *fm)
 {
   int i;
 
@@ -1741,7 +1739,8 @@ show_factor_matrix (const struct cmd_factor *factor, struct idata *idata, const
 
 
 static void
-show_explained_variance (const struct cmd_factor * factor, struct idata *idata,
+show_explained_variance (const struct cmd_factor * factor,
+                        const struct idata *idata,
                         const gsl_vector *initial_eigenvalues,
                         const gsl_vector *extracted_eigenvalues,
                         const gsl_vector *rotated_loadings)
@@ -1969,7 +1968,7 @@ show_factor_correlation (const struct cmd_factor * factor, const gsl_matrix *fcm
   for (i = 0 ; i < fcm->size1; ++i)
     {
       for (j = 0 ; j < fcm->size2; ++j)
-       tab_double (t, heading_columns + i,  heading_rows +j, 0,
+       tab_double (t, heading_columns + j,  heading_rows + i, 0,
                    gsl_matrix_get (fcm, i, j), NULL, RC_OTHER);
     }
 
@@ -2065,7 +2064,7 @@ show_correlation_matrix (const struct cmd_factor *factor, const struct idata *id
          for (i = 0; i < factor->n_vars; ++i)
            {
              for (j = 0; j < factor->n_vars; ++j)
-               tab_double (t, heading_columns + i,  y + j, 0, gsl_matrix_get (idata->mm.corr, i, j), NULL, RC_OTHER);
+               tab_double (t, heading_columns + j,  y + i, 0, gsl_matrix_get (idata->mm.corr, i, j), NULL, RC_OTHER);
            }
        }
 
@@ -2084,7 +2083,7 @@ show_correlation_matrix (const struct cmd_factor *factor, const struct idata *id
                  if (i == j)
                    continue;
 
-                 tab_double (t, heading_columns + i,  y + j, 0, significance_of_correlation (rho, w), NULL, RC_PVALUE);
+                 tab_double (t, heading_columns + j,  y + i, 0, significance_of_correlation (rho, w), NULL, RC_PVALUE);
                }
            }
        }
@@ -2100,6 +2099,90 @@ show_correlation_matrix (const struct cmd_factor *factor, const struct idata *id
   tab_submit (t);
 }
 
+static void
+show_covariance_matrix (const struct cmd_factor *factor, const struct idata *idata)
+{
+  struct tab_table *t ;
+  size_t i, j;
+  int y_pos_corr = -1;
+  int suffix_rows = 0;
+
+  const int heading_rows = 1;
+  const int heading_columns = 1;
+
+  int nc = heading_columns ;
+  int nr = heading_rows ;
+  int n_data_sets = 0;
+
+  if (factor->print & PRINT_COVARIANCE)
+    {
+      y_pos_corr = n_data_sets;
+      n_data_sets++;
+      nc = heading_columns + factor->n_vars;
+    }
+
+  nr += n_data_sets * factor->n_vars;
+
+  /* If the table would contain only headings, don't bother rendering it */
+  if (nr <= heading_rows && suffix_rows == 0)
+    return;
+
+  t = tab_create (nc, nr + suffix_rows);
+
+  tab_title (t, _("Covariance Matrix"));
+
+  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
+
+  if (nr > heading_rows)
+    {
+      tab_headers (t, heading_columns, 0, heading_rows, 0);
+
+      tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+
+      /* Outline the box */
+      tab_box (t,
+              TAL_2, TAL_2,
+              -1, -1,
+              0, 0,
+              nc - 1, nr - 1);
+
+      /* Vertical lines */
+      tab_box (t,
+              -1, -1,
+              -1, TAL_1,
+              heading_columns, 0,
+              nc - 1, nr - 1);
+
+
+      for (i = 0; i < factor->n_vars; ++i)
+       tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i]));
+
+
+      for (i = 0 ; i < n_data_sets; ++i)
+       {
+         int y = heading_rows + i * factor->n_vars;
+         size_t v;
+         for (v = 0; v < factor->n_vars; ++v)
+           tab_text (t, heading_columns -1, y + v, TAT_TITLE, var_to_string (factor->vars[v]));
+
+         tab_hline (t, TAL_1, 0, nc - 1, y);
+       }
+
+      if (factor->print & PRINT_COVARIANCE)
+       {
+         const double y = heading_rows + y_pos_corr;
+
+         for (i = 0; i < factor->n_vars; ++i)
+           {
+             for (j = 0; j < factor->n_vars; ++j)
+               tab_double (t, heading_columns + j,  y + i, 0, gsl_matrix_get (idata->mm.cov, i, j), NULL, RC_OTHER);
+           }
+       }
+    }
+
+  tab_submit (t);
+}
+
 
 static void
 do_factor (const struct cmd_factor *factor, struct casereader *r)
@@ -2131,13 +2214,22 @@ do_factor (const struct cmd_factor *factor, struct casereader *r)
   do_factor_by_matrix (factor, idata);
 
  finish:
+  gsl_matrix_free (idata->mm.corr);
+  gsl_matrix_free (idata->mm.cov);
+
   idata_free (idata);
   casereader_destroy (r);
 }
 
-static void
+static bool
 do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata)
 {
+  if (!idata->mm.cov && !idata->mm.corr)
+    {
+      msg (ME, _("The dataset has no complete covariance or correlation matrix."));
+      return false;
+    }
+
   if (idata->mm.cov && !idata->mm.corr)
     idata->mm.corr = correlation_from_covariance (idata->mm.cov, idata->mm.var_matrix);
   if (idata->mm.corr && !idata->mm.cov)
@@ -2295,6 +2387,7 @@ do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata)
     }
 
   show_correlation_matrix (factor, idata);
+  show_covariance_matrix (factor, idata);
   if (idata->cvm)
     covariance_destroy (idata->cvm);