1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2021 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <gsl/gsl_blas.h>
20 #include <gsl/gsl_eigen.h>
21 #include <gsl/gsl_linalg.h>
22 #include <gsl/gsl_matrix.h>
23 #include <gsl/gsl_permutation.h>
24 #include <gsl/gsl_randist.h>
25 #include <gsl/gsl_vector.h>
30 #include "data/any-reader.h"
31 #include "data/any-writer.h"
32 #include "data/casereader.h"
33 #include "data/casewriter.h"
34 #include "data/data-in.h"
35 #include "data/data-out.h"
36 #include "data/dataset.h"
37 #include "data/dictionary.h"
38 #include "data/file-handle-def.h"
39 #include "language/command.h"
40 #include "language/data-io/data-reader.h"
41 #include "language/data-io/data-writer.h"
42 #include "language/data-io/file-handle.h"
43 #include "language/lexer/format-parser.h"
44 #include "language/lexer/lexer.h"
45 #include "language/lexer/variable-parser.h"
46 #include "libpspp/array.h"
47 #include "libpspp/assertion.h"
48 #include "libpspp/compiler.h"
49 #include "libpspp/hmap.h"
50 #include "libpspp/i18n.h"
51 #include "libpspp/misc.h"
52 #include "libpspp/str.h"
53 #include "libpspp/string-array.h"
54 #include "libpspp/stringi-set.h"
55 #include "libpspp/u8-line.h"
56 #include "math/random.h"
57 #include "output/driver.h"
58 #include "output/output-item.h"
59 #include "output/pivot-table.h"
61 #include "gl/c-ctype.h"
62 #include "gl/minmax.h"
66 #define _(msgid) gettext (msgid)
67 #define N_(msgid) (msgid)
71 struct hmap_node hmap_node;
79 struct file_handle *outfile;
80 struct string_array variables;
81 struct string_array fnames;
82 struct string_array snames;
87 /* Execution state. */
88 struct dictionary *dict;
89 struct casewriter *writer;
94 struct file_handle *file;
95 struct dfm_reader *reader;
101 struct dataset *dataset;
102 struct session *session;
106 struct file_handle *prev_save_outfile;
107 struct file_handle *prev_write_outfile;
108 struct msave_common *common;
110 struct file_handle *prev_read_file;
111 struct read_file **read_files;
115 static struct matrix_var *
116 matrix_var_lookup (struct matrix_state *s, struct substring name)
118 struct matrix_var *var;
120 HMAP_FOR_EACH_WITH_HASH (var, struct matrix_var, hmap_node,
121 utf8_hash_case_substring (name, 0), &s->vars)
122 if (!utf8_sscasecmp (ss_cstr (var->name), name))
128 static struct matrix_var *
129 matrix_var_create (struct matrix_state *s, struct substring name)
131 struct matrix_var *var = xmalloc (sizeof *var);
132 *var = (struct matrix_var) { .name = ss_xstrdup (name) };
133 hmap_insert (&s->vars, &var->hmap_node, utf8_hash_case_substring (name, 0));
138 matrix_var_set (struct matrix_var *var, gsl_matrix *value)
140 gsl_matrix_free (var->value);
144 #define MATRIX_FUNCTIONS \
200 enum { m_d_MIN_ARGS = 1, m_d_MAX_ARGS = 1 };
201 enum { m_dd_MIN_ARGS = 2, m_dd_MAX_ARGS = 2 };
202 enum { m_ddd_MIN_ARGS = 3, m_ddd_MAX_ARGS = 3 };
203 enum { m_m_MIN_ARGS = 1, m_m_MAX_ARGS = 1 };
204 enum { m_md_MIN_ARGS = 2, m_md_MAX_ARGS = 2 };
205 enum { m_mdd_MIN_ARGS = 3, m_mdd_MAX_ARGS = 3 };
206 enum { m_mm_MIN_ARGS = 2, m_mm_MAX_ARGS = 2 };
207 enum { m_v_MIN_ARGS = 1, m_v_MAX_ARGS = 1 };
208 enum { d_m_MIN_ARGS = 1, d_m_MAX_ARGS = 1 };
209 enum { m_any_MIN_ARGS = 1, m_any_MAX_ARGS = INT_MAX };
210 enum { IDENT_MIN_ARGS = 1, IDENT_MAX_ARGS = 2 };
212 typedef gsl_matrix *matrix_proto_m_d (double);
213 typedef gsl_matrix *matrix_proto_m_dd (double, double);
214 typedef gsl_matrix *matrix_proto_m_ddd (double, double, double);
215 typedef gsl_matrix *matrix_proto_m_m (gsl_matrix *);
216 typedef gsl_matrix *matrix_proto_m_md (gsl_matrix *, double);
217 typedef gsl_matrix *matrix_proto_m_mdd (gsl_matrix *, double, double);
218 typedef gsl_matrix *matrix_proto_m_mm (gsl_matrix *, gsl_matrix *);
219 typedef gsl_matrix *matrix_proto_m_v (gsl_vector *);
220 typedef double matrix_proto_d_m (gsl_matrix *);
221 typedef gsl_matrix *matrix_proto_m_any (gsl_matrix *[], size_t n);
222 typedef gsl_matrix *matrix_proto_IDENT (double, double);
224 #define F(NAME, PROTOTYPE) static matrix_proto_##PROTOTYPE matrix_eval_##NAME;
228 /* Matrix expressions. */
235 #define F(NAME, PROTOTYPE) MOP_F_##NAME,
239 /* Elementwise and scalar arithmetic. */
240 MOP_NEGATE, /* unary - */
241 MOP_ADD_ELEMS, /* + */
242 MOP_SUB_ELEMS, /* - */
243 MOP_MUL_ELEMS, /* &* */
244 MOP_DIV_ELEMS, /* / and &/ */
245 MOP_EXP_ELEMS, /* &** */
247 MOP_SEQ_BY, /* a:b:c */
249 /* Matrix arithmetic. */
251 MOP_EXP_MAT, /* ** */
268 MOP_PASTE_HORZ, /* a, b, c, ... */
269 MOP_PASTE_VERT, /* a; b; c; ... */
273 MOP_VEC_INDEX, /* x(y) */
274 MOP_VEC_ALL, /* x(:) */
275 MOP_MAT_INDEX, /* x(y,z) */
276 MOP_ROW_INDEX, /* x(y,:) */
277 MOP_COL_INDEX, /* x(:,z) */
284 MOP_EOF, /* EOF('file') */
292 struct matrix_expr **subs;
297 struct matrix_var *variable;
298 struct read_file *eof;
303 matrix_expr_destroy (struct matrix_expr *e)
310 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
341 for (size_t i = 0; i < e->n_subs; i++)
342 matrix_expr_destroy (e->subs[i]);
354 static struct matrix_expr *
355 matrix_expr_create_subs (enum matrix_op op, struct matrix_expr **subs,
358 struct matrix_expr *e = xmalloc (sizeof *e);
359 *e = (struct matrix_expr) {
361 .subs = xmemdup (subs, n_subs * sizeof *subs),
367 static struct matrix_expr *
368 matrix_expr_create_0 (enum matrix_op op)
370 struct matrix_expr *sub;
371 return matrix_expr_create_subs (op, &sub, 0);
374 static struct matrix_expr *
375 matrix_expr_create_1 (enum matrix_op op, struct matrix_expr *sub)
377 return matrix_expr_create_subs (op, &sub, 1);
380 static struct matrix_expr *
381 matrix_expr_create_2 (enum matrix_op op,
382 struct matrix_expr *sub0, struct matrix_expr *sub1)
384 struct matrix_expr *subs[] = { sub0, sub1 };
385 return matrix_expr_create_subs (op, subs, sizeof subs / sizeof *subs);
388 static struct matrix_expr *
389 matrix_expr_create_3 (enum matrix_op op, struct matrix_expr *sub0,
390 struct matrix_expr *sub1, struct matrix_expr *sub2)
392 struct matrix_expr *subs[] = { sub0, sub1, sub2 };
393 return matrix_expr_create_subs (op, subs, sizeof subs / sizeof *subs);
396 static struct matrix_expr *
397 matrix_expr_create_number (double number)
399 struct matrix_expr *e = xmalloc (sizeof *e);
400 *e = (struct matrix_expr) { .op = MOP_NUMBER, .number = number };
404 static struct matrix_expr *matrix_parse_or_xor (struct matrix_state *);
406 static struct matrix_expr *
407 matrix_parse_curly_comma (struct matrix_state *s)
409 struct matrix_expr *lhs = matrix_parse_or_xor (s);
413 while (lex_match (s->lexer, T_COMMA))
415 struct matrix_expr *rhs = matrix_parse_or_xor (s);
418 matrix_expr_destroy (lhs);
421 lhs = matrix_expr_create_2 (MOP_PASTE_HORZ, lhs, rhs);
426 static struct matrix_expr *
427 matrix_parse_curly_semi (struct matrix_state *s)
429 if (lex_token (s->lexer) == T_RCURLY)
430 return matrix_expr_create_0 (MOP_EMPTY);
432 struct matrix_expr *lhs = matrix_parse_curly_comma (s);
436 while (lex_match (s->lexer, T_SEMICOLON))
438 struct matrix_expr *rhs = matrix_parse_curly_comma (s);
441 matrix_expr_destroy (lhs);
444 lhs = matrix_expr_create_2 (MOP_PASTE_VERT, lhs, rhs);
449 #define MATRIX_FOR_ALL_ELEMENTS(D, Y, X, M) \
450 for (size_t Y = 0; Y < (M)->size1; Y++) \
451 for (size_t X = 0; X < (M)->size2; X++) \
452 for (double *D = gsl_matrix_ptr ((M), Y, X); D; D = NULL)
455 is_vector (const gsl_matrix *m)
457 return m->size1 <= 1 || m->size2 <= 1;
461 to_vector (gsl_matrix *m)
463 return (m->size1 == 1
464 ? gsl_matrix_row (m, 0).vector
465 : gsl_matrix_column (m, 0).vector);
470 matrix_eval_ABS (gsl_matrix *m)
472 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
478 matrix_eval_ALL (gsl_matrix *m)
480 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
487 matrix_eval_ANY (gsl_matrix *m)
489 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
496 matrix_eval_ARSIN (gsl_matrix *m)
498 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
504 matrix_eval_ARTAN (gsl_matrix *m)
506 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
512 matrix_eval_BLOCK (gsl_matrix *m[], size_t n)
516 for (size_t i = 0; i < n; i++)
521 gsl_matrix *block = gsl_matrix_calloc (r, c);
523 for (size_t i = 0; i < n; i++)
525 for (size_t y = 0; y < m[i]->size1; y++)
526 for (size_t x = 0; x < m[i]->size2; x++)
527 gsl_matrix_set (block, r + y, c + x, gsl_matrix_get (m[i], y, x));
535 matrix_eval_CHOL (gsl_matrix *m)
537 if (!gsl_linalg_cholesky_decomp1 (m))
539 for (size_t y = 0; y < m->size1; y++)
540 for (size_t x = y + 1; x < m->size2; x++)
541 gsl_matrix_set (m, y, x, gsl_matrix_get (m, x, y));
543 for (size_t y = 0; y < m->size1; y++)
544 for (size_t x = 0; x < y; x++)
545 gsl_matrix_set (m, y, x, 0);
550 msg (SE, _("Input to CHOL function is not positive-definite."));
556 matrix_eval_col_extremum (gsl_matrix *m, bool min)
561 return gsl_matrix_alloc (1, 0);
563 gsl_matrix *cext = gsl_matrix_alloc (1, m->size2);
564 for (size_t x = 0; x < m->size2; x++)
566 double ext = gsl_matrix_get (m, 0, x);
567 for (size_t y = 1; y < m->size1; y++)
569 double value = gsl_matrix_get (m, y, x);
570 if (min ? value < ext : value > ext)
573 gsl_matrix_set (cext, 0, x, ext);
579 matrix_eval_CMAX (gsl_matrix *m)
581 return matrix_eval_col_extremum (m, false);
585 matrix_eval_CMIN (gsl_matrix *m)
587 return matrix_eval_col_extremum (m, true);
591 matrix_eval_COS (gsl_matrix *m)
593 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
599 matrix_eval_col_sum (gsl_matrix *m, bool square)
604 return gsl_matrix_alloc (1, 0);
606 gsl_matrix *result = gsl_matrix_alloc (1, m->size2);
607 for (size_t x = 0; x < m->size2; x++)
610 for (size_t y = 0; y < m->size1; y++)
612 double d = gsl_matrix_get (m, y, x);
613 sum += square ? pow2 (d) : d;
615 gsl_matrix_set (result, 0, x, sum);
621 matrix_eval_CSSQ (gsl_matrix *m)
623 return matrix_eval_col_sum (m, true);
627 matrix_eval_CSUM (gsl_matrix *m)
629 return matrix_eval_col_sum (m, false);
633 compare_double_3way (const void *a_, const void *b_)
635 const double *a = a_;
636 const double *b = b_;
637 return *a < *b ? -1 : *a > *b;
641 matrix_eval_DESIGN (gsl_matrix *m)
643 double *tmp = xmalloc (m->size1 * m->size2 * sizeof *tmp);
644 gsl_matrix m2 = gsl_matrix_view_array (tmp, m->size2, m->size1).matrix;
645 gsl_matrix_transpose_memcpy (&m2, m);
647 for (size_t y = 0; y < m2.size1; y++)
648 qsort (tmp + y * m2.size2, m2.size2, sizeof *tmp, compare_double_3way);
650 size_t *n = xcalloc (m2.size1, sizeof *n);
652 for (size_t i = 0; i < m2.size1; i++)
654 double *row = tmp + m2.size2 * i;
655 for (size_t j = 0; j < m2.size2; )
658 for (k = j + 1; k < m2.size2; k++)
659 if (row[j] != row[k])
661 row[n[i]++] = row[j];
666 msg (MW, _("Column %zu in DESIGN argument has constant value."), i + 1);
671 gsl_matrix *result = gsl_matrix_alloc (m->size1, n_total);
673 for (size_t i = 0; i < m->size2; i++)
678 const double *unique = tmp + m2.size2 * i;
679 for (size_t j = 0; j < n[i]; j++, x++)
681 double value = unique[j];
682 for (size_t y = 0; y < m->size1; y++)
683 gsl_matrix_set (result, y, x, gsl_matrix_get (m, y, i) == value);
694 matrix_eval_DET (gsl_matrix *m)
696 gsl_permutation *p = gsl_permutation_alloc (m->size1);
698 gsl_linalg_LU_decomp (m, p, &signum);
699 gsl_permutation_free (p);
700 return gsl_linalg_LU_det (m, signum);
704 matrix_eval_DIAG (gsl_matrix *m)
706 gsl_matrix *diag = gsl_matrix_alloc (MIN (m->size1, m->size2), 1);
707 for (size_t i = 0; i < diag->size1; i++)
708 gsl_matrix_set (diag, i, 0, gsl_matrix_get (m, i, i));
713 is_symmetric (const gsl_matrix *m)
715 if (m->size1 != m->size2)
718 for (size_t y = 0; y < m->size1; y++)
719 for (size_t x = 0; x < y; x++)
720 if (gsl_matrix_get (m, y, x) != gsl_matrix_get (m, x, y))
727 compare_double_desc (const void *a_, const void *b_)
729 const double *a = a_;
730 const double *b = b_;
731 return *a > *b ? -1 : *a < *b;
735 matrix_eval_EVAL (gsl_matrix *m)
737 if (!is_symmetric (m))
739 msg (SE, _("Argument of EVAL must be symmetric."));
743 gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc (m->size1);
744 gsl_matrix *eval = gsl_matrix_alloc (m->size1, 1);
745 gsl_vector v_eval = to_vector (eval);
746 gsl_eigen_symm (m, &v_eval, w);
747 gsl_eigen_symm_free (w);
749 assert (v_eval.stride == 1);
750 qsort (v_eval.data, v_eval.size, sizeof *v_eval.data, compare_double_desc);
756 matrix_eval_EXP (gsl_matrix *m)
758 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
763 /* From https://gist.github.com/turingbirds/5e99656e08dbe1324c99, where it was
766 Charl Linssen <charl@itfromb.it>
770 matrix_eval_GINV (gsl_matrix *A)
775 gsl_matrix *tmp_mat = NULL;
778 /* libgsl SVD can only handle the case m <= n, so transpose matrix. */
779 tmp_mat = gsl_matrix_alloc (m, n);
780 gsl_matrix_transpose_memcpy (tmp_mat, A);
788 gsl_matrix *V = gsl_matrix_alloc (m, m);
789 gsl_vector *u = gsl_vector_alloc (m);
791 gsl_vector *tmp_vec = gsl_vector_alloc (m);
792 gsl_linalg_SV_decomp (A, V, u, tmp_vec);
793 gsl_vector_free (tmp_vec);
796 gsl_matrix *Sigma_pinv = gsl_matrix_alloc (m, n);
797 gsl_matrix_set_zero (Sigma_pinv);
798 double cutoff = 1e-15 * gsl_vector_max (u);
800 for (size_t i = 0; i < m; ++i)
802 double x = gsl_vector_get (u, i);
803 gsl_matrix_set (Sigma_pinv, i, i, x > cutoff ? 1.0 / x : 0);
806 /* libgsl SVD yields "thin" SVD - pad to full matrix by adding zeros */
807 gsl_matrix *U = gsl_matrix_calloc (n, n);
808 for (size_t i = 0; i < n; i++)
809 for (size_t j = 0; j < m; j++)
810 gsl_matrix_set (U, i, j, gsl_matrix_get (A, i, j));
812 /* two dot products to obtain pseudoinverse */
813 gsl_matrix *tmp_mat2 = gsl_matrix_alloc (m, n);
814 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1., V, Sigma_pinv, 0., tmp_mat2);
819 A_pinv = gsl_matrix_alloc (n, m);
820 gsl_blas_dgemm (CblasNoTrans, CblasTrans, 1., U, tmp_mat2, 0., A_pinv);
824 A_pinv = gsl_matrix_alloc (m, n);
825 gsl_blas_dgemm (CblasNoTrans, CblasTrans, 1., tmp_mat2, U, 0., A_pinv);
828 gsl_matrix_free (tmp_mat);
829 gsl_matrix_free (tmp_mat2);
831 gsl_matrix_free (Sigma_pinv);
845 grade_compare_3way (const void *a_, const void *b_)
847 const struct grade *a = a_;
848 const struct grade *b = b_;
850 return (a->value < b->value ? -1
851 : a->value > b->value ? 1
859 matrix_eval_GRADE (gsl_matrix *m)
861 size_t n = m->size1 * m->size2;
862 struct grade *grades = xmalloc (n * sizeof *grades);
865 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
866 grades[i++] = (struct grade) { .y = y, .x = x, .value = *d };
867 qsort (grades, n, sizeof *grades, grade_compare_3way);
869 for (size_t i = 0; i < n; i++)
870 gsl_matrix_set (m, grades[i].y, grades[i].x, i + 1);
878 dot (gsl_vector *a, gsl_vector *b)
881 for (size_t i = 0; i < a->size; i++)
882 result += gsl_vector_get (a, i) * gsl_vector_get (b, i);
887 norm2 (gsl_vector *v)
890 for (size_t i = 0; i < v->size; i++)
891 result += pow2 (gsl_vector_get (v, i));
898 return sqrt (norm2 (v));
902 matrix_eval_GSCH (gsl_matrix *v)
904 if (v->size2 < v->size1)
906 msg (SE, _("GSCH requires its argument to have at least as many columns "
907 "as rows, but it has dimensions (%zu,%zu)."),
911 if (!v->size1 || !v->size2)
914 gsl_matrix *u = gsl_matrix_calloc (v->size1, v->size2);
916 for (size_t vx = 0; vx < v->size2; vx++)
918 gsl_vector u_i = gsl_matrix_column (u, ux).vector;
919 gsl_vector v_i = gsl_matrix_column (v, vx).vector;
921 gsl_vector_memcpy (&u_i, &v_i);
922 for (size_t j = 0; j < ux; j++)
924 gsl_vector u_j = gsl_matrix_column (u, j).vector;
925 double scale = dot (&u_j, &u_i) / norm2 (&u_j);
926 for (size_t k = 0; k < u_i.size; k++)
927 gsl_vector_set (&u_i, k, (gsl_vector_get (&u_i, k)
928 - scale * gsl_vector_get (&u_j, k)));
931 double len = norm (&u_i);
934 gsl_vector_scale (&u_i, 1.0 / len);
935 if (++ux >= v->size1)
942 msg (SE, _("Argument to GSCH with dimensions (%zu,%zu) contains only "
943 "%zu linearly independent columns."),
944 v->size1, v->size2, ux);
954 matrix_eval_IDENT (double s1, double s2)
956 if (s1 < 0 || s1 > SIZE_MAX || s2 < 0 || s2 > SIZE_MAX)
958 msg (SE, _("Arguments to IDENT must be non-negative integers."));
962 gsl_matrix *m = gsl_matrix_alloc (s1, s2);
963 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
969 invert_matrix (gsl_matrix *x)
971 gsl_permutation *p = gsl_permutation_alloc (x->size1);
973 gsl_linalg_LU_decomp (x, p, &signum);
974 gsl_linalg_LU_invx (x, p);
975 gsl_permutation_free (p);
979 matrix_eval_INV (gsl_matrix *m)
986 matrix_eval_KRONEKER (gsl_matrix *a, gsl_matrix *b)
988 gsl_matrix *k = gsl_matrix_alloc (a->size1 * b->size1,
989 a->size2 * b->size2);
991 for (size_t ar = 0; ar < a->size1; ar++)
992 for (size_t br = 0; br < b->size1; br++, y++)
995 for (size_t ac = 0; ac < a->size2; ac++)
996 for (size_t bc = 0; bc < b->size2; bc++, x++)
998 double av = gsl_matrix_get (a, ar, ac);
999 double bv = gsl_matrix_get (b, br, bc);
1000 gsl_matrix_set (k, y, x, av * bv);
1007 matrix_eval_LG10 (gsl_matrix *m)
1009 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1015 matrix_eval_LN (gsl_matrix *m)
1017 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1023 matrix_eval_MAGIC_odd (gsl_matrix *m, size_t n)
1025 /* Siamese method: https://en.wikipedia.org/wiki/Siamese_method. */
1028 for (size_t i = 1; i <= n * n; i++)
1030 gsl_matrix_set (m, y, x, i);
1032 size_t y1 = !y ? n - 1 : y - 1;
1033 size_t x1 = x + 1 >= n ? 0 : x + 1;
1034 if (gsl_matrix_get (m, y1, x1) == 0)
1040 y = y + 1 >= n ? 0 : y + 1;
1045 magic_exchange (gsl_matrix *m, size_t y1, size_t x1, size_t y2, size_t x2)
1047 double a = gsl_matrix_get (m, y1, x1);
1048 double b = gsl_matrix_get (m, y2, x2);
1049 gsl_matrix_set (m, y1, x1, b);
1050 gsl_matrix_set (m, y2, x2, a);
1054 matrix_eval_MAGIC_doubly_even (gsl_matrix *m, size_t n)
1058 /* A. Umar, "On the Construction of Even Order Magic Squares",
1059 https://arxiv.org/ftp/arxiv/papers/1202/1202.0948.pdf. */
1061 for (size_t i = 1; i <= n * n / 2; i++)
1063 gsl_matrix_set (m, y, x, i);
1073 for (size_t i = n * n; i > n * n / 2; i--)
1075 gsl_matrix_set (m, y, x, i);
1083 for (size_t y = 0; y < n; y++)
1084 for (size_t x = 0; x < n / 2; x++)
1086 unsigned int d = gsl_matrix_get (m, y, x);
1087 if (d % 2 != (y < n / 2))
1088 magic_exchange (m, y, x, y, n - x - 1);
1093 size_t x1 = n / 2 - 1;
1095 magic_exchange (m, y1, x1, y2, x1);
1096 magic_exchange (m, y1, x2, y2, x2);
1100 matrix_eval_MAGIC_singly_even (gsl_matrix *m, size_t n)
1102 /* A. Umar, "On the Construction of Even Order Magic Squares",
1103 https://arxiv.org/ftp/arxiv/papers/1202/1202.0948.pdf. */
1107 for (size_t i = 1; ; i++)
1109 gsl_matrix_set (m, y, x, i);
1110 if (++y == n / 2 - 1)
1122 for (size_t i = n * n; ; i--)
1124 gsl_matrix_set (m, y, x, i);
1125 if (++y == n / 2 - 1)
1134 for (size_t y = 0; y < n; y++)
1135 if (y != n / 2 - 1 && y != n / 2)
1136 for (size_t x = 0; x < n / 2; x++)
1138 unsigned int d = gsl_matrix_get (m, y, x);
1139 if (d % 2 != (y < n / 2))
1140 magic_exchange (m, y, x, y, n - x - 1);
1143 size_t a0 = (n * n - 2 * n) / 2 + 1;
1144 for (size_t i = 0; i < n / 2; i++)
1147 gsl_matrix_set (m, n / 2, i, a);
1148 gsl_matrix_set (m, n / 2 - 1, i, (n * n + 1) - a);
1150 for (size_t i = 0; i < n / 2; i++)
1152 size_t a = a0 + i + n / 2;
1153 gsl_matrix_set (m, n / 2 - 1, n - i - 1, a);
1154 gsl_matrix_set (m, n / 2, n - i - 1, (n * n + 1) - a);
1156 for (size_t x = 1; x < n / 2; x += 2)
1157 magic_exchange (m, n / 2, x, n / 2 - 1, x);
1158 for (size_t x = n / 2 + 2; x <= n - 3; x += 2)
1159 magic_exchange (m, n / 2, x, n / 2 - 1, x);
1160 size_t x1 = n / 2 - 2;
1161 size_t x2 = n / 2 + 1;
1162 size_t y1 = n / 2 - 2;
1163 size_t y2 = n / 2 + 1;
1164 magic_exchange (m, y1, x1, y2, x1);
1165 magic_exchange (m, y1, x2, y2, x2);
1169 matrix_eval_MAGIC (double n_)
1171 if (n_ < 3 || n_ >= sqrt (SIZE_MAX))
1173 msg (SE, _("MAGIC argument must be an integer 3 or greater."));
1178 gsl_matrix *m = gsl_matrix_calloc (n, n);
1180 matrix_eval_MAGIC_odd (m, n);
1182 matrix_eval_MAGIC_singly_even (m, n);
1184 matrix_eval_MAGIC_doubly_even (m, n);
1189 matrix_eval_MAKE (double r, double c, double value)
1191 if (r < 0 || r >= SIZE_MAX || c < 0 || c >= SIZE_MAX)
1193 msg (SE, _("Size arguments to MAKE must be integers."));
1197 gsl_matrix *m = gsl_matrix_alloc (r, c);
1198 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1204 matrix_eval_MDIAG (gsl_vector *v)
1206 gsl_matrix *m = gsl_matrix_calloc (v->size, v->size);
1207 gsl_vector diagonal = gsl_matrix_diagonal (m).vector;
1208 gsl_vector_memcpy (&diagonal, v);
1213 matrix_eval_MMAX (gsl_matrix *m)
1215 return gsl_matrix_max (m);
1219 matrix_eval_MMIN (gsl_matrix *m)
1221 return gsl_matrix_min (m);
1225 matrix_eval_MOD (gsl_matrix *m, double divisor)
1229 msg (SE, _("Divisor argument to MOD function must be nonzero."));
1233 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1234 *d = fmod (*d, divisor);
1239 matrix_eval_MSSQ (gsl_matrix *m)
1242 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1248 matrix_eval_MSUM (gsl_matrix *m)
1251 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1257 matrix_eval_NCOL (gsl_matrix *m)
1263 matrix_eval_NROW (gsl_matrix *m)
1269 matrix_eval_RANK (gsl_matrix *m)
1271 gsl_vector *tau = gsl_vector_alloc (MIN (m->size1, m->size2));
1272 gsl_linalg_QR_decomp (m, tau);
1273 gsl_vector_free (tau);
1275 return gsl_linalg_QRPT_rank (m, -1);
1279 matrix_eval_RESHAPE (gsl_matrix *m, double r_, double c_)
1281 if (r_ < 0 || r_ >= SIZE_MAX || c_ < 0 || c_ >= SIZE_MAX)
1283 msg (SE, _("Arguments 2 and 3 to RESHAPE must be integers."));
1288 if (size_overflow_p (xtimes (r, xmax (c, 1))) || c * r != m->size1 * m->size2)
1290 msg (SE, _("Product of RESHAPE arguments 2 and 3 differ from "
1291 "product of matrix dimensions."));
1295 gsl_matrix *dst = gsl_matrix_alloc (r, c);
1298 MATRIX_FOR_ALL_ELEMENTS (d, y2, x2, m)
1300 gsl_matrix_set (dst, y1, x1, *d);
1311 matrix_eval_row_extremum (gsl_matrix *m, bool min)
1316 return gsl_matrix_alloc (0, 1);
1318 gsl_matrix *rext = gsl_matrix_alloc (m->size1, 1);
1319 for (size_t y = 0; y < m->size1; y++)
1321 double ext = gsl_matrix_get (m, y, 0);
1322 for (size_t x = 1; x < m->size2; x++)
1324 double value = gsl_matrix_get (m, y, x);
1325 if (min ? value < ext : value > ext)
1328 gsl_matrix_set (rext, y, 0, ext);
1334 matrix_eval_RMAX (gsl_matrix *m)
1336 return matrix_eval_row_extremum (m, false);
1340 matrix_eval_RMIN (gsl_matrix *m)
1342 return matrix_eval_row_extremum (m, true);
1346 matrix_eval_RND (gsl_matrix *m)
1348 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1360 rank_compare_3way (const void *a_, const void *b_)
1362 const struct rank *a = a_;
1363 const struct rank *b = b_;
1365 return a->value < b->value ? -1 : a->value > b->value;
1369 matrix_eval_RNKORDER (gsl_matrix *m)
1371 size_t n = m->size1 * m->size2;
1372 struct rank *ranks = xmalloc (n * sizeof *ranks);
1374 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1375 ranks[i++] = (struct rank) { .y = y, .x = x, .value = *d };
1376 qsort (ranks, n, sizeof *ranks, rank_compare_3way);
1378 for (size_t i = 0; i < n; )
1381 for (j = i + 1; j < n; j++)
1382 if (ranks[i].value != ranks[j].value)
1385 double rank = (i + j + 1.0) / 2.0;
1386 for (size_t k = i; k < j; k++)
1387 gsl_matrix_set (m, ranks[k].y, ranks[k].x, rank);
1398 matrix_eval_row_sum (gsl_matrix *m, bool square)
1403 return gsl_matrix_alloc (0, 1);
1405 gsl_matrix *result = gsl_matrix_alloc (m->size1, 1);
1406 for (size_t y = 0; y < m->size1; y++)
1409 for (size_t x = 0; x < m->size2; x++)
1411 double d = gsl_matrix_get (m, y, x);
1412 sum += square ? pow2 (d) : d;
1414 gsl_matrix_set (result, y, 0, sum);
1420 matrix_eval_RSSQ (gsl_matrix *m)
1422 return matrix_eval_row_sum (m, true);
1426 matrix_eval_RSUM (gsl_matrix *m)
1428 return matrix_eval_row_sum (m, false);
1432 matrix_eval_SIN (gsl_matrix *m)
1434 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1440 matrix_eval_SOLVE (gsl_matrix *m1, gsl_matrix *m2)
1442 if (m1->size1 != m2->size1)
1444 msg (SE, _("SOLVE requires its arguments to have the same number of "
1445 "rows, but the first argument has dimensions (%zu,%zu) and "
1446 "the second (%zu,%zu)."),
1447 m1->size1, m1->size2,
1448 m2->size1, m2->size2);
1452 gsl_matrix *x = gsl_matrix_alloc (m2->size1, m2->size2);
1453 gsl_permutation *p = gsl_permutation_alloc (m1->size1);
1455 gsl_linalg_LU_decomp (m1, p, &signum);
1456 for (size_t i = 0; i < m2->size2; i++)
1458 gsl_vector bi = gsl_matrix_column (m2, i).vector;
1459 gsl_vector xi = gsl_matrix_column (x, i).vector;
1460 gsl_linalg_LU_solve (m1, p, &bi, &xi);
1462 gsl_permutation_free (p);
1467 matrix_eval_SQRT (gsl_matrix *m)
1469 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1473 msg (SE, _("Argument to SQRT must be nonnegative."));
1482 matrix_eval_SSCP (gsl_matrix *m)
1484 gsl_matrix *sscp = gsl_matrix_alloc (m->size2, m->size2);
1485 gsl_blas_dgemm (CblasTrans, CblasNoTrans, 1.0, m, m, 0.0, sscp);
1490 matrix_eval_SVAL (gsl_matrix *m)
1492 gsl_matrix *tmp_mat = NULL;
1493 if (m->size2 > m->size1)
1495 tmp_mat = gsl_matrix_alloc (m->size2, m->size1);
1496 gsl_matrix_transpose_memcpy (tmp_mat, m);
1501 gsl_matrix *V = gsl_matrix_alloc (m->size2, m->size2);
1502 gsl_vector *S = gsl_vector_alloc (m->size2);
1503 gsl_vector *work = gsl_vector_alloc (m->size2);
1504 gsl_linalg_SV_decomp (m, V, S, work);
1506 gsl_matrix *vals = gsl_matrix_alloc (m->size2, 1);
1507 for (size_t i = 0; i < m->size2; i++)
1508 gsl_matrix_set (vals, i, 0, gsl_vector_get (S, i));
1510 gsl_matrix_free (V);
1511 gsl_vector_free (S);
1512 gsl_vector_free (work);
1513 gsl_matrix_free (tmp_mat);
1519 matrix_eval_SWEEP (gsl_matrix *m, double d)
1521 if (d < 1 || d > SIZE_MAX)
1523 msg (SE, _("Scalar argument to SWEEP must be integer."));
1527 if (k >= MIN (m->size1, m->size2))
1529 msg (SE, _("Scalar argument to SWEEP must be integer less than or "
1530 "equal to the smaller of the matrix argument's rows and "
1535 double m_kk = gsl_matrix_get (m, k, k);
1536 if (fabs (m_kk) > 1e-19)
1538 gsl_matrix *a = gsl_matrix_alloc (m->size1, m->size2);
1539 MATRIX_FOR_ALL_ELEMENTS (a_ij, i, j, a)
1541 double m_ij = gsl_matrix_get (m, i, j);
1542 double m_ik = gsl_matrix_get (m, i, k);
1543 double m_kj = gsl_matrix_get (m, k, j);
1544 *a_ij = (i != k && j != k ? m_ij * m_kk - m_ik * m_kj
1553 for (size_t i = 0; i < m->size1; i++)
1555 gsl_matrix_set (m, i, k, 0);
1556 gsl_matrix_set (m, k, i, 0);
1563 matrix_eval_TRACE (gsl_matrix *m)
1566 size_t n = MIN (m->size1, m->size2);
1567 for (size_t i = 0; i < n; i++)
1568 sum += gsl_matrix_get (m, i, i);
1573 matrix_eval_T (gsl_matrix *m)
1575 return matrix_eval_TRANSPOS (m);
1579 matrix_eval_TRANSPOS (gsl_matrix *m)
1581 if (m->size1 == m->size2)
1583 gsl_matrix_transpose (m);
1588 gsl_matrix *t = gsl_matrix_alloc (m->size2, m->size1);
1589 gsl_matrix_transpose_memcpy (t, m);
1595 matrix_eval_TRUNC (gsl_matrix *m)
1597 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1603 matrix_eval_UNIFORM (double r_, double c_)
1605 if (r_ < 0 || r_ >= SIZE_MAX || c_ < 0 || c_ >= SIZE_MAX)
1607 msg (SE, _("Arguments to UNIFORM must be integers."));
1612 if (size_overflow_p (xtimes (r, xmax (c, 1))))
1614 msg (SE, _("Product of arguments to UNIFORM exceeds memory size."));
1618 gsl_matrix *m = gsl_matrix_alloc (r, c);
1619 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1620 *d = gsl_ran_flat (get_rng (), 0, 1);
1624 struct matrix_function
1628 size_t min_args, max_args;
1631 static struct matrix_expr *matrix_parse_expr (struct matrix_state *);
1633 static const struct matrix_function *
1634 matrix_parse_function_name (const char *token)
1636 static const struct matrix_function functions[] =
1638 #define F(NAME, PROTO) { #NAME, MOP_F_##NAME, PROTO##_MIN_ARGS, PROTO##_MAX_ARGS },
1642 enum { N_FUNCTIONS = sizeof functions / sizeof *functions };
1644 for (size_t i = 0; i < N_FUNCTIONS; i++)
1646 if (lex_id_match_n (ss_cstr (functions[i].name), ss_cstr (token), 3))
1647 return &functions[i];
1652 static struct read_file *
1653 read_file_create (struct matrix_state *s, struct file_handle *fh)
1655 for (size_t i = 0; i < s->n_read_files; i++)
1657 struct read_file *rf = s->read_files[i];
1665 struct read_file *rf = xmalloc (sizeof *rf);
1666 *rf = (struct read_file) { .file = fh };
1668 s->read_files = xrealloc (s->read_files,
1669 (s->n_read_files + 1) * sizeof *s->read_files);
1670 s->read_files[s->n_read_files++] = rf;
1674 static struct dfm_reader *
1675 read_file_open (struct read_file *rf)
1678 rf->reader = dfm_open_reader (rf->file, NULL, rf->encoding);
1683 read_file_destroy (struct read_file *rf)
1687 fh_unref (rf->file);
1688 dfm_close_reader (rf->reader);
1689 free (rf->encoding);
1695 matrix_parse_function (struct matrix_state *s, const char *token,
1696 struct matrix_expr **exprp)
1699 if (lex_next_token (s->lexer, 1) != T_LPAREN)
1702 if (lex_match_id (s->lexer, "EOF"))
1705 struct file_handle *fh = fh_parse (s->lexer, FH_REF_FILE, s->session);
1709 if (!lex_force_match (s->lexer, T_RPAREN))
1715 struct read_file *rf = read_file_create (s, fh);
1717 struct matrix_expr *e = xmalloc (sizeof *e);
1718 *e = (struct matrix_expr) { .op = MOP_EOF, .eof = rf };
1723 const struct matrix_function *f = matrix_parse_function_name (token);
1727 lex_get_n (s->lexer, 2);
1729 struct matrix_expr *e = xmalloc (sizeof *e);
1730 *e = (struct matrix_expr) { .op = f->op, .subs = NULL };
1732 size_t allocated_subs = 0;
1735 struct matrix_expr *sub = matrix_parse_expr (s);
1739 if (e->n_subs >= allocated_subs)
1740 e->subs = x2nrealloc (e->subs, &allocated_subs, sizeof *e->subs);
1741 e->subs[e->n_subs++] = sub;
1743 while (lex_match (s->lexer, T_COMMA));
1744 if (!lex_force_match (s->lexer, T_RPAREN))
1751 matrix_expr_destroy (e);
1755 static struct matrix_expr *
1756 matrix_parse_primary (struct matrix_state *s)
1758 if (lex_is_number (s->lexer))
1760 double number = lex_number (s->lexer);
1762 return matrix_expr_create_number (number);
1764 else if (lex_is_string (s->lexer))
1766 char string[sizeof (double)];
1767 buf_copy_str_rpad (string, sizeof string, lex_tokcstr (s->lexer), ' ');
1771 memcpy (&number, string, sizeof number);
1772 return matrix_expr_create_number (number);
1774 else if (lex_match (s->lexer, T_LPAREN))
1776 struct matrix_expr *e = matrix_parse_or_xor (s);
1777 if (!e || !lex_force_match (s->lexer, T_RPAREN))
1779 matrix_expr_destroy (e);
1784 else if (lex_match (s->lexer, T_LCURLY))
1786 struct matrix_expr *e = matrix_parse_curly_semi (s);
1787 if (!e || !lex_force_match (s->lexer, T_RCURLY))
1789 matrix_expr_destroy (e);
1794 else if (lex_token (s->lexer) == T_ID)
1796 struct matrix_expr *retval;
1797 if (matrix_parse_function (s, lex_tokcstr (s->lexer), &retval))
1800 struct matrix_var *var = matrix_var_lookup (s, lex_tokss (s->lexer));
1803 lex_error (s->lexer, _("Unknown variable %s."),
1804 lex_tokcstr (s->lexer));
1809 struct matrix_expr *e = xmalloc (sizeof *e);
1810 *e = (struct matrix_expr) { .op = MOP_VARIABLE, .variable = var };
1813 else if (lex_token (s->lexer) == T_ALL)
1815 struct matrix_expr *retval;
1816 if (matrix_parse_function (s, "ALL", &retval))
1820 lex_error (s->lexer, NULL);
1824 static struct matrix_expr *matrix_parse_postfix (struct matrix_state *);
1827 matrix_parse_index_expr (struct matrix_state *s, struct matrix_expr **indexp)
1829 if (lex_match (s->lexer, T_COLON))
1836 *indexp = matrix_parse_expr (s);
1837 return *indexp != NULL;
1841 static struct matrix_expr *
1842 matrix_parse_postfix (struct matrix_state *s)
1844 struct matrix_expr *lhs = matrix_parse_primary (s);
1845 if (!lhs || !lex_match (s->lexer, T_LPAREN))
1848 struct matrix_expr *i0;
1849 if (!matrix_parse_index_expr (s, &i0))
1851 matrix_expr_destroy (lhs);
1854 if (lex_match (s->lexer, T_RPAREN))
1856 ? matrix_expr_create_2 (MOP_VEC_INDEX, lhs, i0)
1857 : matrix_expr_create_1 (MOP_VEC_ALL, lhs));
1858 else if (lex_match (s->lexer, T_COMMA))
1860 struct matrix_expr *i1;
1861 if (!matrix_parse_index_expr (s, &i1)
1862 || !lex_force_match (s->lexer, T_RPAREN))
1864 matrix_expr_destroy (lhs);
1865 matrix_expr_destroy (i0);
1866 matrix_expr_destroy (i1);
1869 return (i0 && i1 ? matrix_expr_create_3 (MOP_MAT_INDEX, lhs, i0, i1)
1870 : i0 ? matrix_expr_create_2 (MOP_ROW_INDEX, lhs, i0)
1871 : i1 ? matrix_expr_create_2 (MOP_COL_INDEX, lhs, i1)
1876 lex_error_expecting (s->lexer, "`)'", "`,'");
1881 static struct matrix_expr *
1882 matrix_parse_unary (struct matrix_state *s)
1884 if (lex_match (s->lexer, T_DASH))
1886 struct matrix_expr *lhs = matrix_parse_unary (s);
1887 return lhs ? matrix_expr_create_1 (MOP_NEGATE, lhs) : NULL;
1889 else if (lex_match (s->lexer, T_PLUS))
1890 return matrix_parse_unary (s);
1892 return matrix_parse_postfix (s);
1895 static struct matrix_expr *
1896 matrix_parse_seq (struct matrix_state *s)
1898 struct matrix_expr *start = matrix_parse_unary (s);
1899 if (!start || !lex_match (s->lexer, T_COLON))
1902 struct matrix_expr *end = matrix_parse_unary (s);
1905 matrix_expr_destroy (start);
1909 if (lex_match (s->lexer, T_COLON))
1911 struct matrix_expr *increment = matrix_parse_unary (s);
1914 matrix_expr_destroy (start);
1915 matrix_expr_destroy (end);
1918 return matrix_expr_create_3 (MOP_SEQ_BY, start, end, increment);
1921 return matrix_expr_create_2 (MOP_SEQ, start, end);
1924 static struct matrix_expr *
1925 matrix_parse_exp (struct matrix_state *s)
1927 struct matrix_expr *lhs = matrix_parse_seq (s);
1934 if (lex_match (s->lexer, T_EXP))
1936 else if (lex_match_phrase (s->lexer, "&**"))
1941 struct matrix_expr *rhs = matrix_parse_seq (s);
1944 matrix_expr_destroy (lhs);
1947 lhs = matrix_expr_create_2 (op, lhs, rhs);
1951 static struct matrix_expr *
1952 matrix_parse_mul_div (struct matrix_state *s)
1954 struct matrix_expr *lhs = matrix_parse_exp (s);
1961 if (lex_match (s->lexer, T_ASTERISK))
1963 else if (lex_match (s->lexer, T_SLASH))
1965 else if (lex_match_phrase (s->lexer, "&*"))
1967 else if (lex_match_phrase (s->lexer, "&/"))
1972 struct matrix_expr *rhs = matrix_parse_exp (s);
1975 matrix_expr_destroy (lhs);
1978 lhs = matrix_expr_create_2 (op, lhs, rhs);
1982 static struct matrix_expr *
1983 matrix_parse_add_sub (struct matrix_state *s)
1985 struct matrix_expr *lhs = matrix_parse_mul_div (s);
1992 if (lex_match (s->lexer, T_PLUS))
1994 else if (lex_match (s->lexer, T_DASH))
1996 else if (lex_token (s->lexer) == T_NEG_NUM)
2001 struct matrix_expr *rhs = matrix_parse_mul_div (s);
2004 matrix_expr_destroy (lhs);
2007 lhs = matrix_expr_create_2 (op, lhs, rhs);
2011 static struct matrix_expr *
2012 matrix_parse_relational (struct matrix_state *s)
2014 struct matrix_expr *lhs = matrix_parse_add_sub (s);
2021 if (lex_match (s->lexer, T_GT))
2023 else if (lex_match (s->lexer, T_GE))
2025 else if (lex_match (s->lexer, T_LT))
2027 else if (lex_match (s->lexer, T_LE))
2029 else if (lex_match (s->lexer, T_EQUALS) || lex_match (s->lexer, T_EQ))
2031 else if (lex_match (s->lexer, T_NE))
2036 struct matrix_expr *rhs = matrix_parse_add_sub (s);
2039 matrix_expr_destroy (lhs);
2042 lhs = matrix_expr_create_2 (op, lhs, rhs);
2046 static struct matrix_expr *
2047 matrix_parse_not (struct matrix_state *s)
2049 if (lex_match (s->lexer, T_NOT))
2051 struct matrix_expr *lhs = matrix_parse_not (s);
2052 return lhs ? matrix_expr_create_1 (MOP_NOT, lhs) : NULL;
2055 return matrix_parse_relational (s);
2058 static struct matrix_expr *
2059 matrix_parse_and (struct matrix_state *s)
2061 struct matrix_expr *lhs = matrix_parse_not (s);
2065 while (lex_match (s->lexer, T_AND))
2067 struct matrix_expr *rhs = matrix_parse_not (s);
2070 matrix_expr_destroy (lhs);
2073 lhs = matrix_expr_create_2 (MOP_AND, lhs, rhs);
2078 static struct matrix_expr *
2079 matrix_parse_or_xor (struct matrix_state *s)
2081 struct matrix_expr *lhs = matrix_parse_and (s);
2088 if (lex_match (s->lexer, T_OR))
2090 else if (lex_match_id (s->lexer, "XOR"))
2095 struct matrix_expr *rhs = matrix_parse_and (s);
2098 matrix_expr_destroy (lhs);
2101 lhs = matrix_expr_create_2 (op, lhs, rhs);
2105 static struct matrix_expr *
2106 matrix_parse_expr (struct matrix_state *s)
2108 return matrix_parse_or_xor (s);
2111 /* Expression evaluation. */
2114 matrix_op_eval (enum matrix_op op, double a, double b)
2118 case MOP_ADD_ELEMS: return a + b;
2119 case MOP_SUB_ELEMS: return a - b;
2120 case MOP_MUL_ELEMS: return a * b;
2121 case MOP_DIV_ELEMS: return a / b;
2122 case MOP_EXP_ELEMS: return pow (a, b);
2123 case MOP_GT: return a > b;
2124 case MOP_GE: return a >= b;
2125 case MOP_LT: return a < b;
2126 case MOP_LE: return a <= b;
2127 case MOP_EQ: return a == b;
2128 case MOP_NE: return a != b;
2129 case MOP_AND: return (a > 0) && (b > 0);
2130 case MOP_OR: return (a > 0) || (b > 0);
2131 case MOP_XOR: return (a > 0) != (b > 0);
2133 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
2142 case MOP_PASTE_HORZ:
2143 case MOP_PASTE_VERT:
2159 matrix_op_name (enum matrix_op op)
2163 case MOP_ADD_ELEMS: return "+";
2164 case MOP_SUB_ELEMS: return "-";
2165 case MOP_MUL_ELEMS: return "&*";
2166 case MOP_DIV_ELEMS: return "&/";
2167 case MOP_EXP_ELEMS: return "&**";
2168 case MOP_GT: return ">";
2169 case MOP_GE: return ">=";
2170 case MOP_LT: return "<";
2171 case MOP_LE: return "<=";
2172 case MOP_EQ: return "=";
2173 case MOP_NE: return "<>";
2174 case MOP_AND: return "AND";
2175 case MOP_OR: return "OR";
2176 case MOP_XOR: return "XOR";
2178 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
2187 case MOP_PASTE_HORZ:
2188 case MOP_PASTE_VERT:
2204 is_scalar (const gsl_matrix *m)
2206 return m->size1 == 1 && m->size2 == 1;
2210 to_scalar (const gsl_matrix *m)
2212 assert (is_scalar (m));
2213 return gsl_matrix_get (m, 0, 0);
2217 matrix_expr_evaluate_elementwise (enum matrix_op op,
2218 gsl_matrix *a, gsl_matrix *b)
2222 double be = to_scalar (b);
2223 for (size_t r = 0; r < a->size1; r++)
2224 for (size_t c = 0; c < a->size2; c++)
2226 double *ae = gsl_matrix_ptr (a, r, c);
2227 *ae = matrix_op_eval (op, *ae, be);
2231 else if (is_scalar (a))
2233 double ae = to_scalar (a);
2234 for (size_t r = 0; r < b->size1; r++)
2235 for (size_t c = 0; c < b->size2; c++)
2237 double *be = gsl_matrix_ptr (b, r, c);
2238 *be = matrix_op_eval (op, ae, *be);
2242 else if (a->size1 == b->size1 && a->size2 == b->size2)
2244 for (size_t r = 0; r < a->size1; r++)
2245 for (size_t c = 0; c < a->size2; c++)
2247 double *ae = gsl_matrix_ptr (a, r, c);
2248 double be = gsl_matrix_get (b, r, c);
2249 *ae = matrix_op_eval (op, *ae, be);
2255 msg (SE, _("Operands to %s must have the same dimensions or one "
2256 "must be a scalar, not matrices with dimensions (%zu,%zu) "
2258 matrix_op_name (op), a->size1, a->size2, b->size1, b->size2);
2264 matrix_expr_evaluate_mul_mat (gsl_matrix *a, gsl_matrix *b)
2266 if (is_scalar (a) || is_scalar (b))
2267 return matrix_expr_evaluate_elementwise (MOP_MUL_ELEMS, a, b);
2269 if (a->size2 != b->size1)
2271 msg (SE, _("Matrices with dimensions (%zu,%zu) and (%zu,%zu) are "
2272 "not conformable for multiplication."),
2273 a->size1, a->size2, b->size1, b->size2);
2277 gsl_matrix *c = gsl_matrix_alloc (a->size1, b->size2);
2278 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, a, b, 0.0, c);
2283 swap_matrix (gsl_matrix **a, gsl_matrix **b)
2285 gsl_matrix *tmp = *a;
2291 mul_matrix (gsl_matrix **z, const gsl_matrix *x, const gsl_matrix *y,
2294 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, x, y, 0.0, *tmp);
2295 swap_matrix (z, tmp);
2299 square_matrix (gsl_matrix **x, gsl_matrix **tmp)
2301 mul_matrix (x, *x, *x, tmp);
2305 matrix_expr_evaluate_exp_mat (gsl_matrix *x_, gsl_matrix *b)
2308 if (x->size1 != x->size2)
2310 msg (SE, _("Matrix exponentation with ** requires a square matrix on "
2311 "the left-hand size, not one with dimensions (%zu,%zu)."),
2312 x->size1, x->size2);
2317 msg (SE, _("Matrix exponentiation with ** requires a scalar on the "
2318 "right-hand side, not a matrix with dimensions (%zu,%zu)."),
2319 b->size1, b->size2);
2322 double bf = to_scalar (b);
2323 if (bf != floor (bf) || bf <= LONG_MIN || bf > LONG_MAX)
2325 msg (SE, _("Exponent %.1f in matrix multiplication is non-integer "
2326 "or outside the valid range."), bf);
2331 gsl_matrix *y_ = gsl_matrix_alloc (x->size1, x->size2);
2333 gsl_matrix_set_identity (y);
2337 gsl_matrix *t_ = gsl_matrix_alloc (x->size1, x->size2);
2339 for (unsigned long int n = labs (bl); n > 1; n /= 2)
2342 mul_matrix (&y, x, y, &t);
2343 square_matrix (&x, &t);
2346 square_matrix (&x, &t);
2348 mul_matrix (&y, x, y, &t);
2352 /* Garbage collection.
2354 There are three matrices: 'x_', 'y_', and 't_', and 'x', 'y', and 't' are
2355 a permutation of them. We are returning one of them; that one must not be
2356 destroyed. We must not destroy 'x_' because the caller owns it. */
2358 gsl_matrix_free (y_);
2360 gsl_matrix_free (t_);
2366 matrix_expr_evaluate_seq (gsl_matrix *start_, gsl_matrix *end_,
2369 if (!is_scalar (start_) || !is_scalar (end_) || (by_ && !is_scalar (by_)))
2371 msg (SE, _("All operands of : operator must be scalars."));
2375 long int start = to_scalar (start_);
2376 long int end = to_scalar (end_);
2377 long int by = by_ ? to_scalar (by_) : 1;
2381 msg (SE, _("The increment operand to : must be nonzero."));
2385 long int n = (end > start && by > 0 ? (end - start + by) / by
2386 : end < start && by < 0 ? (start - end - by) / -by
2388 gsl_matrix *m = gsl_matrix_alloc (1, n);
2389 for (long int i = 0; i < n; i++)
2390 gsl_matrix_set (m, 0, i, start + i * by);
2395 matrix_expr_evaluate_not (gsl_matrix *a)
2397 for (size_t r = 0; r < a->size1; r++)
2398 for (size_t c = 0; c < a->size2; c++)
2400 double *ae = gsl_matrix_ptr (a, r, c);
2407 matrix_expr_evaluate_paste_horz (gsl_matrix *a, gsl_matrix *b)
2409 if (a->size1 != b->size1)
2411 if (!a->size1 || !a->size2)
2413 else if (!b->size1 || !b->size2)
2416 msg (SE, _("All columns in a matrix must have the same number of rows, "
2417 "but this tries to paste matrices with %zu and %zu rows."),
2418 a->size1, b->size1);
2422 gsl_matrix *c = gsl_matrix_alloc (a->size1, a->size2 + b->size2);
2423 for (size_t y = 0; y < a->size1; y++)
2425 for (size_t x = 0; x < a->size2; x++)
2426 gsl_matrix_set (c, y, x, gsl_matrix_get (a, y, x));
2427 for (size_t x = 0; x < b->size2; x++)
2428 gsl_matrix_set (c, y, x + a->size2, gsl_matrix_get (b, y, x));
2434 matrix_expr_evaluate_paste_vert (gsl_matrix *a, gsl_matrix *b)
2436 if (a->size2 != b->size2)
2438 if (!a->size1 || !a->size2)
2440 else if (!b->size1 || !b->size2)
2443 msg (SE, _("All rows in a matrix must have the same number of columns, "
2444 "but this tries to stack matrices with %zu and %zu columns."),
2445 a->size2, b->size2);
2449 gsl_matrix *c = gsl_matrix_alloc (a->size1 + b->size1, a->size2);
2450 for (size_t x = 0; x < a->size2; x++)
2452 for (size_t y = 0; y < a->size1; y++)
2453 gsl_matrix_set (c, y, x, gsl_matrix_get (a, y, x));
2454 for (size_t y = 0; y < b->size1; y++)
2455 gsl_matrix_set (c, y + a->size1, x, gsl_matrix_get (b, y, x));
2461 matrix_to_vector (gsl_matrix *m)
2464 gsl_vector v = to_vector (m);
2465 assert (v.block == m->block || !v.block);
2469 return xmemdup (&v, sizeof v);
2483 #define INDEX_VECTOR_INIT (struct index_vector) { .n = 0 }
2486 matrix_normalize_index_vector (const gsl_matrix *m, size_t size,
2487 enum index_type index_type, size_t other_size,
2488 struct index_vector *iv)
2497 msg (SE, _("Vector index must be scalar or vector, not a "
2498 "matrix with dimensions (%zu,%zu)."),
2499 m->size1, m->size2);
2503 msg (SE, _("Matrix row index must be scalar or vector, not a "
2504 "matrix with dimensions (%zu,%zu)."),
2505 m->size1, m->size2);
2509 msg (SE, _("Matrix column index must be scalar or vector, not a "
2510 "matrix with dimensions (%zu,%zu)."),
2511 m->size1, m->size2);
2517 gsl_vector v = to_vector (CONST_CAST (gsl_matrix *, m));
2518 *iv = (struct index_vector) {
2519 .indexes = xnmalloc (v.size, sizeof *iv->indexes),
2522 for (size_t i = 0; i < v.size; i++)
2524 double index = gsl_vector_get (&v, i);
2525 if (index < 1 || index >= size + 1)
2530 msg (SE, _("Index %g is out of range for vector "
2531 "with %zu elements."), index, size);
2535 msg (SE, _("%g is not a valid row index for a matrix "
2536 "with dimensions (%zu,%zu)."),
2537 index, size, other_size);
2541 msg (SE, _("%g is not a valid column index for a matrix "
2542 "with dimensions (%zu,%zu)."),
2543 index, other_size, size);
2550 iv->indexes[i] = index - 1;
2556 *iv = (struct index_vector) {
2557 .indexes = xnmalloc (size, sizeof *iv->indexes),
2560 for (size_t i = 0; i < size; i++)
2567 matrix_expr_evaluate_vec_all (gsl_matrix *sm)
2569 if (!is_vector (sm))
2571 msg (SE, _("Vector index operator must be applied to vector, "
2572 "not a matrix with dimensions (%zu,%zu)."),
2573 sm->size1, sm->size2);
2581 matrix_expr_evaluate_vec_index (gsl_matrix *sm, gsl_matrix *im)
2583 if (!matrix_expr_evaluate_vec_all (sm))
2586 gsl_vector sv = to_vector (sm);
2587 struct index_vector iv;
2588 if (!matrix_normalize_index_vector (im, sv.size, IV_VECTOR, 0, &iv))
2591 gsl_matrix *dm = gsl_matrix_alloc (sm->size1 == 1 ? 1 : iv.n,
2592 sm->size1 == 1 ? iv.n : 1);
2593 gsl_vector dv = to_vector (dm);
2594 for (size_t dx = 0; dx < iv.n; dx++)
2596 size_t sx = iv.indexes[dx];
2597 gsl_vector_set (&dv, dx, gsl_vector_get (&sv, sx));
2605 matrix_expr_evaluate_mat_index (gsl_matrix *sm, gsl_matrix *im0,
2608 struct index_vector iv0;
2609 if (!matrix_normalize_index_vector (im0, sm->size1, IV_ROW, sm->size2, &iv0))
2612 struct index_vector iv1;
2613 if (!matrix_normalize_index_vector (im1, sm->size2, IV_COLUMN, sm->size1,
2620 gsl_matrix *dm = gsl_matrix_alloc (iv0.n, iv1.n);
2621 for (size_t dy = 0; dy < iv0.n; dy++)
2623 size_t sy = iv0.indexes[dy];
2625 for (size_t dx = 0; dx < iv1.n; dx++)
2627 size_t sx = iv1.indexes[dx];
2628 gsl_matrix_set (dm, dy, dx, gsl_matrix_get (sm, sy, sx));
2636 #define F(NAME, PROTOTYPE) \
2637 static gsl_matrix *matrix_expr_evaluate_##PROTOTYPE ( \
2638 const char *name, gsl_matrix *[], size_t, \
2639 matrix_proto_##PROTOTYPE *);
2644 check_scalar_arg (const char *name, gsl_matrix *subs[], size_t index)
2646 if (!is_scalar (subs[index]))
2648 msg (SE, _("Function %s argument %zu must be a scalar, "
2649 "but it has dimensions (%zu,%zu)."),
2650 name, index + 1, subs[index]->size1, subs[index]->size2);
2657 check_vector_arg (const char *name, gsl_matrix *subs[], size_t index)
2659 if (!is_vector (subs[index]))
2661 msg (SE, _("Function %s argument %zu must be a vector, "
2662 "but it has dimensions (%zu,%zu)."),
2663 name, index + 1, subs[index]->size1, subs[index]->size2);
2670 to_scalar_args (const char *name, gsl_matrix *subs[], size_t n_subs, double d[])
2672 for (size_t i = 0; i < n_subs; i++)
2674 if (!check_scalar_arg (name, subs, i))
2676 d[i] = to_scalar (subs[i]);
2682 matrix_expr_evaluate_m_d (const char *name,
2683 gsl_matrix *subs[], size_t n_subs,
2684 matrix_proto_m_d *f)
2686 assert (n_subs == 1);
2689 return to_scalar_args (name, subs, n_subs, &d) ? f(d) : NULL;
2693 matrix_expr_evaluate_m_dd (const char *name,
2694 gsl_matrix *subs[], size_t n_subs,
2695 matrix_proto_m_dd *f)
2697 assert (n_subs == 2);
2700 return to_scalar_args (name, subs, n_subs, d) ? f(d[0], d[1]) : NULL;
2704 matrix_expr_evaluate_m_ddd (const char *name,
2705 gsl_matrix *subs[], size_t n_subs,
2706 matrix_proto_m_ddd *f)
2708 assert (n_subs == 3);
2711 return to_scalar_args (name, subs, n_subs, d) ? f(d[0], d[1], d[2]) : NULL;
2715 matrix_expr_evaluate_m_m (const char *name UNUSED,
2716 gsl_matrix *subs[], size_t n_subs,
2717 matrix_proto_m_m *f)
2719 assert (n_subs == 1);
2724 matrix_expr_evaluate_m_md (const char *name UNUSED,
2725 gsl_matrix *subs[], size_t n_subs,
2726 matrix_proto_m_md *f)
2728 assert (n_subs == 2);
2729 if (!check_scalar_arg (name, subs, 1))
2731 return f (subs[0], to_scalar (subs[1]));
2735 matrix_expr_evaluate_m_mdd (const char *name UNUSED,
2736 gsl_matrix *subs[], size_t n_subs,
2737 matrix_proto_m_mdd *f)
2739 assert (n_subs == 3);
2740 if (!check_scalar_arg (name, subs, 1) || !check_scalar_arg (name, subs, 2))
2742 return f (subs[0], to_scalar (subs[1]), to_scalar (subs[2]));
2746 matrix_expr_evaluate_m_mm (const char *name UNUSED,
2747 gsl_matrix *subs[], size_t n_subs,
2748 matrix_proto_m_mm *f)
2750 assert (n_subs == 2);
2751 return f (subs[0], subs[1]);
2755 matrix_expr_evaluate_m_v (const char *name,
2756 gsl_matrix *subs[], size_t n_subs,
2757 matrix_proto_m_v *f)
2759 assert (n_subs == 1);
2760 if (!check_vector_arg (name, subs, 0))
2762 gsl_vector v = to_vector (subs[0]);
2767 matrix_expr_evaluate_d_m (const char *name UNUSED,
2768 gsl_matrix *subs[], size_t n_subs,
2769 matrix_proto_d_m *f)
2771 assert (n_subs == 1);
2773 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2774 gsl_matrix_set (m, 0, 0, f (subs[0]));
2779 matrix_expr_evaluate_m_any (const char *name UNUSED,
2780 gsl_matrix *subs[], size_t n_subs,
2781 matrix_proto_m_any *f)
2783 return f (subs, n_subs);
2787 matrix_expr_evaluate_IDENT (const char *name,
2788 gsl_matrix *subs[], size_t n_subs,
2789 matrix_proto_IDENT *f)
2791 assert (n_subs <= 2);
2794 if (!to_scalar_args (name, subs, n_subs, d))
2797 return f (d[0], d[n_subs - 1]);
2801 matrix_expr_evaluate (const struct matrix_expr *e)
2803 if (e->op == MOP_NUMBER)
2805 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2806 gsl_matrix_set (m, 0, 0, e->number);
2809 else if (e->op == MOP_VARIABLE)
2811 const gsl_matrix *src = e->variable->value;
2814 msg (SE, _("Uninitialized variable %s used in expression."),
2819 gsl_matrix *dst = gsl_matrix_alloc (src->size1, src->size2);
2820 gsl_matrix_memcpy (dst, src);
2823 else if (e->op == MOP_EOF)
2825 struct dfm_reader *reader = read_file_open (e->eof);
2826 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2827 gsl_matrix_set (m, 0, 0, !reader || dfm_eof (reader));
2831 enum { N_LOCAL = 3 };
2832 gsl_matrix *local_subs[N_LOCAL];
2833 gsl_matrix **subs = (e->n_subs < N_LOCAL
2835 : xmalloc (e->n_subs * sizeof *subs));
2837 for (size_t i = 0; i < e->n_subs; i++)
2839 subs[i] = matrix_expr_evaluate (e->subs[i]);
2842 for (size_t j = 0; j < i; j++)
2843 gsl_matrix_free (subs[j]);
2844 if (subs != local_subs)
2850 gsl_matrix *result = NULL;
2853 #define F(NAME, PROTOTYPE) \
2854 case MOP_F_##NAME: \
2855 result = matrix_expr_evaluate_##PROTOTYPE (#NAME, \
2857 matrix_eval_##NAME); \
2863 gsl_matrix_scale (subs[0], -1.0);
2881 result = matrix_expr_evaluate_elementwise (e->op, subs[0], subs[1]);
2885 result = matrix_expr_evaluate_not (subs[0]);
2889 result = matrix_expr_evaluate_seq (subs[0], subs[1], NULL);
2893 result = matrix_expr_evaluate_seq (subs[0], subs[1], subs[2]);
2897 result = matrix_expr_evaluate_mul_mat (subs[0], subs[1]);
2901 result = matrix_expr_evaluate_exp_mat (subs[0], subs[1]);
2904 case MOP_PASTE_HORZ:
2905 result = matrix_expr_evaluate_paste_horz (subs[0], subs[1]);
2908 case MOP_PASTE_VERT:
2909 result = matrix_expr_evaluate_paste_vert (subs[0], subs[1]);
2913 result = gsl_matrix_alloc (0, 0);
2917 result = matrix_expr_evaluate_vec_index (subs[0], subs[1]);
2921 result = matrix_expr_evaluate_vec_all (subs[0]);
2925 result = matrix_expr_evaluate_mat_index (subs[0], subs[1], subs[2]);
2929 result = matrix_expr_evaluate_mat_index (subs[0], subs[1], NULL);
2933 result = matrix_expr_evaluate_mat_index (subs[0], NULL, subs[1]);
2942 for (size_t i = 0; i < e->n_subs; i++)
2943 if (subs[i] != result)
2944 gsl_matrix_free (subs[i]);
2945 if (subs != local_subs)
2951 matrix_expr_evaluate_scalar (const struct matrix_expr *e, const char *context,
2954 gsl_matrix *m = matrix_expr_evaluate (e);
2960 msg (SE, _("Expression for %s must evaluate to scalar, "
2961 "not a matrix with dimensions (%zu,%zu)."),
2962 context, m->size1, m->size2);
2963 gsl_matrix_free (m);
2968 gsl_matrix_free (m);
2973 matrix_expr_evaluate_integer (const struct matrix_expr *e, const char *context,
2977 if (!matrix_expr_evaluate_scalar (e, context, &d))
2981 if (d < LONG_MIN || d > LONG_MAX)
2983 msg (SE, _("Expression for %s is outside the integer range."), context);
2990 struct matrix_lvalue
2992 struct matrix_var *var;
2993 struct matrix_expr *indexes[2];
2998 matrix_lvalue_destroy (struct matrix_lvalue *lvalue)
3002 for (size_t i = 0; i < lvalue->n_indexes; i++)
3003 matrix_expr_destroy (lvalue->indexes[i]);
3008 static struct matrix_lvalue *
3009 matrix_lvalue_parse (struct matrix_state *s)
3011 struct matrix_lvalue *lvalue = xzalloc (sizeof *lvalue);
3012 if (!lex_force_id (s->lexer))
3014 lvalue->var = matrix_var_lookup (s, lex_tokss (s->lexer));
3015 if (lex_next_token (s->lexer, 1) == T_LPAREN)
3019 msg (SE, _("Undefined variable %s."), lex_tokcstr (s->lexer));
3024 lex_get_n (s->lexer, 2);
3026 if (!matrix_parse_index_expr (s, &lvalue->indexes[0]))
3028 lvalue->n_indexes++;
3030 if (lex_match (s->lexer, T_COMMA))
3032 if (!matrix_parse_index_expr (s, &lvalue->indexes[1]))
3034 lvalue->n_indexes++;
3036 if (!lex_force_match (s->lexer, T_RPAREN))
3042 lvalue->var = matrix_var_create (s, lex_tokss (s->lexer));
3048 matrix_lvalue_destroy (lvalue);
3053 matrix_lvalue_evaluate_vector (struct matrix_expr *e, size_t size,
3054 enum index_type index_type, size_t other_size,
3055 struct index_vector *iv)
3060 m = matrix_expr_evaluate (e);
3067 bool ok = matrix_normalize_index_vector (m, size, index_type,
3069 gsl_matrix_free (m);
3074 matrix_lvalue_assign_vector (struct matrix_lvalue *lvalue,
3075 struct index_vector *iv, gsl_matrix *sm)
3077 gsl_vector dv = to_vector (lvalue->var->value);
3079 /* Convert source matrix 'sm' to source vector 'sv'. */
3080 if (!is_vector (sm))
3082 msg (SE, _("Can't assign matrix with dimensions (%zu,%zu) to subvector."),
3083 sm->size1, sm->size2);
3086 gsl_vector sv = to_vector (sm);
3087 if (iv->n != sv.size)
3089 msg (SE, _("Can't assign vector with %zu elements "
3090 "to subvector with %zu."), sv.size, iv->n);
3094 /* Assign elements. */
3095 for (size_t x = 0; x < iv->n; x++)
3096 gsl_vector_set (&dv, iv->indexes[x], gsl_vector_get (&sv, x));
3101 matrix_lvalue_assign_matrix (struct matrix_lvalue *lvalue,
3102 struct index_vector *iv0,
3103 struct index_vector *iv1, gsl_matrix *sm)
3105 gsl_matrix *dm = lvalue->var->value;
3107 /* Convert source matrix 'sm' to source vector 'sv'. */
3108 if (iv0->n != sm->size1)
3110 msg (SE, _("Row index vector for assignment to %s has %zu elements "
3111 "but source matrix has %zu rows."),
3112 lvalue->var->name, iv0->n, sm->size1);
3115 if (iv1->n != sm->size2)
3117 msg (SE, _("Column index vector for assignment to %s has %zu elements "
3118 "but source matrix has %zu columns."),
3119 lvalue->var->name, iv1->n, sm->size2);
3123 /* Assign elements. */
3124 for (size_t y = 0; y < iv0->n; y++)
3126 size_t f0 = iv0->indexes[y];
3127 for (size_t x = 0; x < iv1->n; x++)
3129 size_t f1 = iv1->indexes[x];
3130 gsl_matrix_set (dm, f0, f1, gsl_matrix_get (sm, y, x));
3136 /* Takes ownership of M. */
3138 matrix_lvalue_assign (struct matrix_lvalue *lvalue,
3139 struct index_vector *iv0, struct index_vector *iv1,
3142 if (!lvalue->n_indexes)
3144 gsl_matrix_free (lvalue->var->value);
3145 lvalue->var->value = sm;
3150 bool ok = (lvalue->n_indexes == 1
3151 ? matrix_lvalue_assign_vector (lvalue, iv0, sm)
3152 : matrix_lvalue_assign_matrix (lvalue, iv0, iv1, sm));
3153 free (iv0->indexes);
3154 free (iv1->indexes);
3155 gsl_matrix_free (sm);
3161 matrix_lvalue_evaluate (struct matrix_lvalue *lvalue,
3162 struct index_vector *iv0,
3163 struct index_vector *iv1)
3165 *iv0 = INDEX_VECTOR_INIT;
3166 *iv1 = INDEX_VECTOR_INIT;
3167 if (!lvalue->n_indexes)
3170 /* Validate destination matrix exists and has the right shape. */
3171 gsl_matrix *dm = lvalue->var->value;
3174 msg (SE, _("Undefined variable %s."), lvalue->var->name);
3177 else if (dm->size1 == 0 || dm->size2 == 0)
3179 msg (SE, _("Cannot index matrix with dimensions (%zu,%zu)."),
3180 dm->size1, dm->size2);
3183 else if (lvalue->n_indexes == 1)
3185 if (!is_vector (dm))
3187 msg (SE, _("Can't use vector indexing on matrix %s with "
3188 "dimensions (%zu,%zu)."),
3189 lvalue->var->name, dm->size1, dm->size2);
3192 return matrix_lvalue_evaluate_vector (lvalue->indexes[0],
3193 MAX (dm->size1, dm->size2),
3198 assert (lvalue->n_indexes == 2);
3199 if (!matrix_lvalue_evaluate_vector (lvalue->indexes[0], dm->size1,
3200 IV_ROW, dm->size2, iv0))
3203 if (!matrix_lvalue_evaluate_vector (lvalue->indexes[1], dm->size2,
3204 IV_COLUMN, dm->size1, iv1))
3206 free (iv0->indexes);
3213 /* Takes ownership of M. */
3215 matrix_lvalue_evaluate_and_assign (struct matrix_lvalue *lvalue, gsl_matrix *sm)
3217 struct index_vector iv0, iv1;
3218 if (!matrix_lvalue_evaluate (lvalue, &iv0, &iv1))
3220 gsl_matrix_free (sm);
3224 return matrix_lvalue_assign (lvalue, &iv0, &iv1, sm);
3228 /* Matrix command. */
3232 struct matrix_cmd **commands;
3236 static void matrix_cmds_uninit (struct matrix_cmds *);
3240 enum matrix_cmd_type
3263 struct compute_command
3265 struct matrix_lvalue *lvalue;
3266 struct matrix_expr *rvalue;
3270 struct print_command
3272 struct matrix_expr *expression;
3273 bool use_default_format;
3274 struct fmt_spec format;
3276 int space; /* -1 means NEWPAGE. */
3280 struct string_array literals; /* CLABELS/RLABELS. */
3281 struct matrix_expr *expr; /* CNAMES/RNAMES. */
3287 struct do_if_command
3291 struct matrix_expr *condition;
3292 struct matrix_cmds commands;
3302 struct matrix_var *var;
3303 struct matrix_expr *start;
3304 struct matrix_expr *end;
3305 struct matrix_expr *increment;
3307 /* Loop conditions. */
3308 struct matrix_expr *top_condition;
3309 struct matrix_expr *bottom_condition;
3312 struct matrix_cmds commands;
3316 struct display_command
3318 struct matrix_state *state;
3324 struct release_command
3326 struct matrix_var **vars;
3333 struct matrix_expr *expression;
3334 struct file_handle *outfile;
3335 struct string_array *variables;
3336 struct matrix_expr *names;
3337 struct stringi_set strings;
3343 struct read_file *rf;
3344 struct matrix_lvalue *dst;
3345 struct matrix_expr *size;
3347 enum fmt_type format;
3355 struct write_command
3357 struct matrix_expr *expression;
3358 struct file_handle *outfile;
3361 enum fmt_type format;
3371 struct matrix_lvalue *dst;
3372 struct file_handle *file;
3374 struct string_array variables;
3375 struct matrix_var *names;
3377 /* Treatment of missing values. */
3382 MGET_ERROR, /* Flag error on command. */
3383 MGET_ACCEPT, /* Accept without change, user-missing only. */
3384 MGET_OMIT, /* Drop this case. */
3385 MGET_RECODE /* Recode to 'substitute'. */
3388 double substitute; /* MGET_RECODE only. */
3394 struct msave_command
3396 struct msave_common *common;
3398 struct matrix_expr *expr;
3399 const char *rowtype;
3400 struct matrix_expr *factors;
3401 struct matrix_expr *splits;
3407 struct matrix_state *state;
3408 struct file_handle *file;
3409 struct stringi_set rowtypes;
3413 struct eigen_command
3415 struct matrix_expr *expr;
3416 struct matrix_var *evec;
3417 struct matrix_var *eval;
3421 struct setdiag_command
3423 struct matrix_var *dst;
3424 struct matrix_expr *expr;
3430 struct matrix_expr *expr;
3431 struct matrix_var *u;
3432 struct matrix_var *s;
3433 struct matrix_var *v;
3439 static struct matrix_cmd *matrix_parse_command (struct matrix_state *);
3440 static bool matrix_cmd_execute (struct matrix_cmd *);
3441 static void matrix_cmd_destroy (struct matrix_cmd *);
3444 static struct matrix_cmd *
3445 matrix_parse_compute (struct matrix_state *s)
3447 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
3448 *cmd = (struct matrix_cmd) {
3449 .type = MCMD_COMPUTE,
3450 .compute = { .lvalue = NULL },
3453 struct compute_command *compute = &cmd->compute;
3454 compute->lvalue = matrix_lvalue_parse (s);
3455 if (!compute->lvalue)
3458 if (!lex_force_match (s->lexer, T_EQUALS))
3461 compute->rvalue = matrix_parse_expr (s);
3462 if (!compute->rvalue)
3468 matrix_cmd_destroy (cmd);
3473 matrix_cmd_execute_compute (struct compute_command *compute)
3475 gsl_matrix *value = matrix_expr_evaluate (compute->rvalue);
3479 matrix_lvalue_evaluate_and_assign (compute->lvalue, value);
3483 print_labels_destroy (struct print_labels *labels)
3487 string_array_destroy (&labels->literals);
3488 matrix_expr_destroy (labels->expr);
3494 parse_literal_print_labels (struct matrix_state *s,
3495 struct print_labels **labelsp)
3497 lex_match (s->lexer, T_EQUALS);
3498 print_labels_destroy (*labelsp);
3499 *labelsp = xzalloc (sizeof **labelsp);
3500 while (lex_token (s->lexer) != T_SLASH
3501 && lex_token (s->lexer) != T_ENDCMD
3502 && lex_token (s->lexer) != T_STOP)
3504 struct string label = DS_EMPTY_INITIALIZER;
3505 while (lex_token (s->lexer) != T_COMMA
3506 && lex_token (s->lexer) != T_SLASH
3507 && lex_token (s->lexer) != T_ENDCMD
3508 && lex_token (s->lexer) != T_STOP)
3510 if (!ds_is_empty (&label))
3511 ds_put_byte (&label, ' ');
3513 if (lex_token (s->lexer) == T_STRING)
3514 ds_put_cstr (&label, lex_tokcstr (s->lexer));
3517 char *rep = lex_next_representation (s->lexer, 0, 0);
3518 ds_put_cstr (&label, rep);
3523 string_array_append_nocopy (&(*labelsp)->literals,
3524 ds_steal_cstr (&label));
3526 if (!lex_match (s->lexer, T_COMMA))
3532 parse_expr_print_labels (struct matrix_state *s, struct print_labels **labelsp)
3534 lex_match (s->lexer, T_EQUALS);
3535 struct matrix_expr *e = matrix_parse_exp (s);
3539 print_labels_destroy (*labelsp);
3540 *labelsp = xzalloc (sizeof **labelsp);
3541 (*labelsp)->expr = e;
3545 static struct matrix_cmd *
3546 matrix_parse_print (struct matrix_state *s)
3548 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
3549 *cmd = (struct matrix_cmd) {
3552 .use_default_format = true,
3556 if (lex_token (s->lexer) != T_SLASH && lex_token (s->lexer) != T_ENDCMD)
3559 for (size_t i = 0; ; i++)
3561 enum token_type t = lex_next_token (s->lexer, i);
3562 if (t == T_LPAREN || t == T_LBRACK || t == T_LCURLY)
3564 else if ((t == T_RPAREN || t == T_RBRACK || t == T_RCURLY) && depth)
3566 else if ((t == T_SLASH && !depth) || t == T_ENDCMD || t == T_STOP)
3569 cmd->print.title = lex_next_representation (s->lexer, 0, i - 1);
3574 cmd->print.expression = matrix_parse_exp (s);
3575 if (!cmd->print.expression)
3579 while (lex_match (s->lexer, T_SLASH))
3581 if (lex_match_id (s->lexer, "FORMAT"))
3583 lex_match (s->lexer, T_EQUALS);
3584 if (!parse_format_specifier (s->lexer, &cmd->print.format))
3586 cmd->print.use_default_format = false;
3588 else if (lex_match_id (s->lexer, "TITLE"))
3590 lex_match (s->lexer, T_EQUALS);
3591 if (!lex_force_string (s->lexer))
3593 free (cmd->print.title);
3594 cmd->print.title = ss_xstrdup (lex_tokss (s->lexer));
3597 else if (lex_match_id (s->lexer, "SPACE"))
3599 lex_match (s->lexer, T_EQUALS);
3600 if (lex_match_id (s->lexer, "NEWPAGE"))
3601 cmd->print.space = -1;
3602 else if (lex_force_int_range (s->lexer, "SPACE", 1, INT_MAX))
3604 cmd->print.space = lex_integer (s->lexer);
3610 else if (lex_match_id (s->lexer, "RLABELS"))
3611 parse_literal_print_labels (s, &cmd->print.rlabels);
3612 else if (lex_match_id (s->lexer, "CLABELS"))
3613 parse_literal_print_labels (s, &cmd->print.clabels);
3614 else if (lex_match_id (s->lexer, "RNAMES"))
3616 if (!parse_expr_print_labels (s, &cmd->print.rlabels))
3619 else if (lex_match_id (s->lexer, "CNAMES"))
3621 if (!parse_expr_print_labels (s, &cmd->print.clabels))
3626 lex_error_expecting (s->lexer, "FORMAT", "TITLE", "SPACE",
3627 "RLABELS", "CLABELS", "RNAMES", "CNAMES");
3635 matrix_cmd_destroy (cmd);
3640 matrix_is_integer (const gsl_matrix *m)
3642 for (size_t y = 0; y < m->size1; y++)
3643 for (size_t x = 0; x < m->size2; x++)
3645 double d = gsl_matrix_get (m, y, x);
3653 matrix_max_magnitude (const gsl_matrix *m)
3656 for (size_t y = 0; y < m->size1; y++)
3657 for (size_t x = 0; x < m->size2; x++)
3659 double d = fabs (gsl_matrix_get (m, y, x));
3667 format_fits (struct fmt_spec format, double x)
3669 char *s = data_out (&(union value) { .f = x }, NULL,
3670 &format, settings_get_fmt_settings ());
3671 bool fits = *s != '*' && !strchr (s, 'E');
3676 static struct fmt_spec
3677 default_format (const gsl_matrix *m, int *log_scale)
3681 double max = matrix_max_magnitude (m);
3683 if (matrix_is_integer (m))
3684 for (int w = 1; w <= 12; w++)
3686 struct fmt_spec format = { .type = FMT_F, .w = w };
3687 if (format_fits (format, -max))
3691 if (max >= 1e9 || max <= 1e-4)
3694 snprintf (s, sizeof s, "%.1e", max);
3696 const char *e = strchr (s, 'e');
3698 *log_scale = atoi (e + 1);
3701 return (struct fmt_spec) { .type = FMT_F, .w = 13, .d = 10 };
3705 trimmed_string (double d)
3707 struct substring s = ss_buffer ((char *) &d, sizeof d);
3708 ss_rtrim (&s, ss_cstr (" "));
3709 return ss_xstrdup (s);
3712 static struct string_array *
3713 print_labels_get (const struct print_labels *labels, size_t n,
3714 const char *prefix, bool truncate)
3719 struct string_array *out = xzalloc (sizeof *out);
3720 if (labels->literals.n)
3721 string_array_clone (out, &labels->literals);
3722 else if (labels->expr)
3724 gsl_matrix *m = matrix_expr_evaluate (labels->expr);
3725 if (m && is_vector (m))
3727 gsl_vector v = to_vector (m);
3728 for (size_t i = 0; i < v.size; i++)
3729 string_array_append_nocopy (out, trimmed_string (
3730 gsl_vector_get (&v, i)));
3732 gsl_matrix_free (m);
3738 string_array_append_nocopy (out, xasprintf ("%s%zu", prefix,
3741 string_array_append (out, "");
3744 string_array_delete (out, out->n - 1);
3747 for (size_t i = 0; i < out->n; i++)
3749 char *s = out->strings[i];
3750 s[strnlen (s, 8)] = '\0';
3757 matrix_cmd_print_space (int space)
3760 output_item_submit (page_break_item_create ());
3761 for (int i = 0; i < space; i++)
3762 output_log ("%s", "");
3766 matrix_cmd_print_text (const struct print_command *print, const gsl_matrix *m,
3767 struct fmt_spec format, int log_scale)
3769 matrix_cmd_print_space (print->space);
3771 output_log ("%s", print->title);
3773 output_log (" 10 ** %d X", log_scale);
3775 struct string_array *clabels = print_labels_get (print->clabels,
3776 m->size2, "col", true);
3777 if (clabels && format.w < 8)
3779 struct string_array *rlabels = print_labels_get (print->rlabels,
3780 m->size1, "row", true);
3784 struct string line = DS_EMPTY_INITIALIZER;
3786 ds_put_byte_multiple (&line, ' ', 8);
3787 for (size_t x = 0; x < m->size2; x++)
3788 ds_put_format (&line, " %*s", format.w, clabels->strings[x]);
3789 output_log_nocopy (ds_steal_cstr (&line));
3792 double scale = pow (10.0, log_scale);
3793 bool numeric = fmt_is_numeric (format.type);
3794 for (size_t y = 0; y < m->size1; y++)
3796 struct string line = DS_EMPTY_INITIALIZER;
3798 ds_put_format (&line, "%-8s", rlabels->strings[y]);
3800 for (size_t x = 0; x < m->size2; x++)
3802 double f = gsl_matrix_get (m, y, x);
3804 ? data_out (&(union value) { .f = f / scale}, NULL,
3805 &format, settings_get_fmt_settings ())
3806 : trimmed_string (f));
3807 ds_put_format (&line, " %s", s);
3810 output_log_nocopy (ds_steal_cstr (&line));
3813 string_array_destroy (rlabels);
3815 string_array_destroy (clabels);
3820 create_print_dimension (struct pivot_table *table, enum pivot_axis_type axis,
3821 const struct print_labels *print_labels, size_t n,
3822 const char *name, const char *prefix)
3824 struct string_array *labels = print_labels_get (print_labels, n, prefix,
3826 struct pivot_dimension *d = pivot_dimension_create (table, axis, name);
3827 for (size_t i = 0; i < n; i++)
3828 pivot_category_create_leaf (
3830 ? pivot_value_new_user_text (labels->strings[i], SIZE_MAX)
3831 : pivot_value_new_integer (i + 1)));
3833 d->hide_all_labels = true;
3834 string_array_destroy (labels);
3839 matrix_cmd_print_tables (const struct print_command *print, const gsl_matrix *m,
3840 struct fmt_spec format, int log_scale)
3842 struct pivot_table *table = pivot_table_create__ (
3843 pivot_value_new_user_text (print->title ? print->title : "", SIZE_MAX),
3846 create_print_dimension (table, PIVOT_AXIS_ROW, print->rlabels, m->size1,
3848 create_print_dimension (table, PIVOT_AXIS_COLUMN, print->clabels, m->size2,
3849 N_("Columns"), "col");
3851 struct pivot_footnote *footnote = NULL;
3854 char *s = xasprintf ("× 10**%d", log_scale);
3855 footnote = pivot_table_create_footnote (
3856 table, pivot_value_new_user_text_nocopy (s));
3859 double scale = pow (10.0, log_scale);
3860 bool numeric = fmt_is_numeric (format.type);
3861 for (size_t y = 0; y < m->size1; y++)
3862 for (size_t x = 0; x < m->size2; x++)
3864 double f = gsl_matrix_get (m, y, x);
3865 struct pivot_value *v;
3868 v = pivot_value_new_number (f / scale);
3869 v->numeric.format = format;
3872 v = pivot_value_new_user_text_nocopy (trimmed_string (f));
3874 pivot_value_add_footnote (v, footnote);
3875 pivot_table_put2 (table, y, x, v);
3878 pivot_table_submit (table);
3882 matrix_cmd_execute_print (const struct print_command *print)
3884 if (print->expression)
3886 gsl_matrix *m = matrix_expr_evaluate (print->expression);
3891 struct fmt_spec format = (print->use_default_format
3892 ? default_format (m, &log_scale)
3895 if (settings_get_mdisplay () == SETTINGS_MDISPLAY_TEXT)
3896 matrix_cmd_print_text (print, m, format, log_scale);
3898 matrix_cmd_print_tables (print, m, format, log_scale);
3900 gsl_matrix_free (m);
3904 matrix_cmd_print_space (print->space);
3906 output_log ("%s", print->title);
3913 matrix_parse_commands (struct matrix_state *s, struct matrix_cmds *c,
3914 const char *command_name,
3915 const char *stop1, const char *stop2)
3917 lex_end_of_command (s->lexer);
3918 lex_discard_rest_of_command (s->lexer);
3920 size_t allocated = 0;
3923 while (lex_token (s->lexer) == T_ENDCMD)
3926 if (lex_at_phrase (s->lexer, stop1)
3927 || (stop2 && lex_at_phrase (s->lexer, stop2)))
3930 if (lex_at_phrase (s->lexer, "END MATRIX"))
3932 msg (SE, _("Premature END MATRIX within %s."), command_name);
3936 struct matrix_cmd *cmd = matrix_parse_command (s);
3940 if (c->n >= allocated)
3941 c->commands = x2nrealloc (c->commands, &allocated, sizeof *c->commands);
3942 c->commands[c->n++] = cmd;
3947 matrix_parse_do_if_clause (struct matrix_state *s,
3948 struct do_if_command *ifc,
3949 bool parse_condition,
3950 size_t *allocated_clauses)
3952 if (ifc->n_clauses >= *allocated_clauses)
3953 ifc->clauses = x2nrealloc (ifc->clauses, allocated_clauses,
3954 sizeof *ifc->clauses);
3955 struct do_if_clause *c = &ifc->clauses[ifc->n_clauses++];
3956 *c = (struct do_if_clause) { .condition = NULL };
3958 if (parse_condition)
3960 c->condition = matrix_parse_expr (s);
3965 return matrix_parse_commands (s, &c->commands, "DO IF", "ELSE", "END IF");
3968 static struct matrix_cmd *
3969 matrix_parse_do_if (struct matrix_state *s)
3971 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
3972 *cmd = (struct matrix_cmd) {
3974 .do_if = { .n_clauses = 0 }
3977 size_t allocated_clauses = 0;
3980 if (!matrix_parse_do_if_clause (s, &cmd->do_if, true, &allocated_clauses))
3983 while (lex_match_phrase (s->lexer, "ELSE IF"));
3985 if (lex_match_id (s->lexer, "ELSE")
3986 && !matrix_parse_do_if_clause (s, &cmd->do_if, false, &allocated_clauses))
3989 if (!lex_match_phrase (s->lexer, "END IF"))
3994 matrix_cmd_destroy (cmd);
3999 matrix_cmd_execute_do_if (struct do_if_command *cmd)
4001 for (size_t i = 0; i < cmd->n_clauses; i++)
4003 struct do_if_clause *c = &cmd->clauses[i];
4007 if (!matrix_expr_evaluate_scalar (c->condition,
4008 i ? "ELSE IF" : "DO IF",
4013 for (size_t j = 0; j < c->commands.n; j++)
4014 if (!matrix_cmd_execute (c->commands.commands[j]))
4021 static struct matrix_cmd *
4022 matrix_parse_loop (struct matrix_state *s)
4024 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4025 *cmd = (struct matrix_cmd) { .type = MCMD_LOOP, .loop = { .var = NULL } };
4027 struct loop_command *loop = &cmd->loop;
4028 if (lex_token (s->lexer) == T_ID && lex_next_token (s->lexer, 1) == T_EQUALS)
4030 struct substring name = lex_tokss (s->lexer);
4031 loop->var = matrix_var_lookup (s, name);
4033 loop->var = matrix_var_create (s, name);
4038 loop->start = matrix_parse_expr (s);
4039 if (!loop->start || !lex_force_match (s->lexer, T_TO))
4042 loop->end = matrix_parse_expr (s);
4046 if (lex_match (s->lexer, T_BY))
4048 loop->increment = matrix_parse_expr (s);
4049 if (!loop->increment)
4054 if (lex_match_id (s->lexer, "IF"))
4056 loop->top_condition = matrix_parse_expr (s);
4057 if (!loop->top_condition)
4061 bool was_in_loop = s->in_loop;
4063 bool ok = matrix_parse_commands (s, &loop->commands, "LOOP",
4065 s->in_loop = was_in_loop;
4069 if (!lex_match_phrase (s->lexer, "END LOOP"))
4072 if (lex_match_id (s->lexer, "IF"))
4074 loop->bottom_condition = matrix_parse_expr (s);
4075 if (!loop->bottom_condition)
4082 matrix_cmd_destroy (cmd);
4087 matrix_cmd_execute_loop (struct loop_command *cmd)
4091 long int increment = 1;
4094 if (!matrix_expr_evaluate_integer (cmd->start, "LOOP", &value)
4095 || !matrix_expr_evaluate_integer (cmd->end, "TO", &end)
4097 && !matrix_expr_evaluate_integer (cmd->increment, "BY",
4101 if (increment > 0 ? value > end
4102 : increment < 0 ? value < end
4107 int mxloops = settings_get_mxloops ();
4108 for (int i = 0; i < mxloops; i++)
4113 && (cmd->var->value->size1 != 1 || cmd->var->value->size2 != 1))
4115 gsl_matrix_free (cmd->var->value);
4116 cmd->var->value = NULL;
4118 if (!cmd->var->value)
4119 cmd->var->value = gsl_matrix_alloc (1, 1);
4121 gsl_matrix_set (cmd->var->value, 0, 0, value);
4124 if (cmd->top_condition)
4127 if (!matrix_expr_evaluate_scalar (cmd->top_condition, "LOOP IF",
4132 for (size_t j = 0; j < cmd->commands.n; j++)
4133 if (!matrix_cmd_execute (cmd->commands.commands[j]))
4136 if (cmd->bottom_condition)
4139 if (!matrix_expr_evaluate_scalar (cmd->bottom_condition,
4140 "END LOOP IF", &d) || d > 0)
4147 if (increment > 0 ? value > end : value < end)
4153 static struct matrix_cmd *
4154 matrix_parse_break (struct matrix_state *s)
4158 msg (SE, _("BREAK not inside LOOP."));
4162 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4163 *cmd = (struct matrix_cmd) { .type = MCMD_BREAK };
4167 static struct matrix_cmd *
4168 matrix_parse_display (struct matrix_state *s)
4170 bool dictionary = false;
4171 bool status = false;
4172 while (lex_token (s->lexer) == T_ID)
4174 if (lex_match_id (s->lexer, "DICTIONARY"))
4176 else if (lex_match_id (s->lexer, "STATUS"))
4180 lex_error_expecting (s->lexer, "DICTIONARY", "STATUS");
4184 if (!dictionary && !status)
4185 dictionary = status = true;
4187 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4188 *cmd = (struct matrix_cmd) {
4189 .type = MCMD_DISPLAY,
4192 .dictionary = dictionary,
4200 compare_matrix_var_pointers (const void *a_, const void *b_)
4202 const struct matrix_var *const *ap = a_;
4203 const struct matrix_var *const *bp = b_;
4204 const struct matrix_var *a = *ap;
4205 const struct matrix_var *b = *bp;
4206 return strcmp (a->name, b->name);
4210 matrix_cmd_execute_display (struct display_command *cmd)
4212 const struct matrix_state *s = cmd->state;
4214 struct pivot_table *table = pivot_table_create (N_("Matrix Variables"));
4215 pivot_dimension_create (
4216 table, PIVOT_AXIS_COLUMN, N_("Property"),
4217 N_("Rows"), N_("Columns"), N_("Size (kB)"));
4219 const struct matrix_var **vars = xmalloc (hmap_count (&s->vars) * sizeof *vars);
4222 const struct matrix_var *var;
4223 HMAP_FOR_EACH (var, struct matrix_var, hmap_node, &s->vars)
4225 vars[n_vars++] = var;
4226 qsort (vars, n_vars, sizeof *vars, compare_matrix_var_pointers);
4228 struct pivot_dimension *rows = pivot_dimension_create (
4229 table, PIVOT_AXIS_ROW, N_("Variable"));
4230 for (size_t i = 0; i < n_vars; i++)
4232 const struct matrix_var *var = vars[i];
4233 pivot_category_create_leaf (
4234 rows->root, pivot_value_new_user_text (var->name, SIZE_MAX));
4236 size_t r = var->value->size1;
4237 size_t c = var->value->size2;
4238 double values[] = { r, c, r * c * sizeof (double) / 1024 };
4239 for (size_t j = 0; j < sizeof values / sizeof *values; j++)
4240 pivot_table_put2 (table, j, i, pivot_value_new_integer (values[j]));
4242 pivot_table_submit (table);
4245 static struct matrix_cmd *
4246 matrix_parse_release (struct matrix_state *s)
4248 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4249 *cmd = (struct matrix_cmd) { .type = MCMD_RELEASE };
4251 size_t allocated_vars = 0;
4252 while (lex_token (s->lexer) == T_ID)
4254 struct matrix_var *var = matrix_var_lookup (s, lex_tokss (s->lexer));
4257 if (cmd->release.n_vars >= allocated_vars)
4258 cmd->release.vars = x2nrealloc (cmd->release.vars, &allocated_vars,
4259 sizeof *cmd->release.vars);
4260 cmd->release.vars[cmd->release.n_vars++] = var;
4263 lex_error (s->lexer, _("Variable name expected."));
4266 if (!lex_match (s->lexer, T_COMMA))
4274 matrix_cmd_execute_release (struct release_command *cmd)
4276 for (size_t i = 0; i < cmd->n_vars; i++)
4278 struct matrix_var *var = cmd->vars[i];
4279 gsl_matrix_free (var->value);
4284 static struct matrix_cmd *
4285 matrix_parse_save (struct matrix_state *s)
4287 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4288 *cmd = (struct matrix_cmd) {
4291 .strings = STRINGI_SET_INITIALIZER (cmd->save.strings)
4295 struct save_command *save = &cmd->save;
4296 save->expression = matrix_parse_exp (s);
4297 if (!save->expression)
4300 while (lex_match (s->lexer, T_SLASH))
4302 if (lex_match_id (s->lexer, "OUTFILE"))
4304 lex_match (s->lexer, T_EQUALS);
4306 fh_unref (save->outfile);
4307 save->outfile = (lex_match (s->lexer, T_ASTERISK)
4309 : fh_parse (s->lexer, FH_REF_FILE, s->session));
4313 else if (lex_match_id (s->lexer, "VARIABLES"))
4315 lex_match (s->lexer, T_EQUALS);
4319 struct dictionary *d = dict_create (get_default_encoding ());
4320 bool ok = parse_DATA_LIST_vars (s->lexer, d, &names, &n,
4321 PV_NO_SCRATCH | PV_NO_DUPLICATE);
4326 string_array_destroy (save->variables);
4327 if (!save->variables)
4328 save->variables = xmalloc (sizeof *save->variables);
4329 *save->variables = (struct string_array) {
4335 else if (lex_match_id (s->lexer, "NAMES"))
4337 lex_match (s->lexer, T_EQUALS);
4338 matrix_expr_destroy (save->names);
4339 save->names = matrix_parse_exp (s);
4343 else if (lex_match_id (s->lexer, "STRINGS"))
4345 lex_match (s->lexer, T_EQUALS);
4346 while (lex_token (s->lexer) == T_ID)
4348 stringi_set_insert (&save->strings, lex_tokcstr (s->lexer));
4350 if (!lex_match (s->lexer, T_COMMA))
4356 lex_error_expecting (s->lexer, "OUTFILE", "VARIABLES", "NAMES",
4364 if (s->prev_save_outfile)
4365 save->outfile = fh_ref (s->prev_save_outfile);
4368 lex_sbc_missing ("OUTFILE");
4372 fh_unref (s->prev_save_outfile);
4373 s->prev_save_outfile = fh_ref (save->outfile);
4375 if (save->variables && save->names)
4377 msg (SW, _("VARIABLES and NAMES both specified; ignoring NAMES."));
4378 matrix_expr_destroy (save->names);
4385 matrix_cmd_destroy (cmd);
4390 matrix_cmd_execute_save (const struct save_command *save)
4392 assert (save->outfile != fh_inline_file ()); /* XXX not yet implemented */
4394 gsl_matrix *m = matrix_expr_evaluate (save->expression);
4399 struct dictionary *dict = dict_create (get_default_encoding ());
4400 struct string_array names = { .n = 0 };
4401 if (save->variables)
4402 string_array_clone (&names, save->variables);
4403 else if (save->names)
4405 gsl_matrix *nm = matrix_expr_evaluate (save->names);
4406 if (nm && is_vector (nm))
4408 gsl_vector nv = to_vector (nm);
4409 for (size_t i = 0; i < nv.size; i++)
4411 char *name = trimmed_string (gsl_vector_get (&nv, i));
4412 if (dict_id_is_valid (dict, name, true))
4413 string_array_append_nocopy (&names, name);
4420 struct stringi_set strings;
4421 stringi_set_clone (&strings, &save->strings);
4423 for (size_t i = 0; dict_get_var_cnt (dict) < m->size2; i++)
4428 name = names.strings[i];
4431 snprintf (tmp_name, sizeof tmp_name, "COL%zu", i + 1);
4435 int width = stringi_set_delete (&strings, name) ? 8 : 0;
4436 struct variable *var = dict_create_var (dict, name, width);
4439 msg (SE, _("Duplicate variable name %s in SAVE statement."),
4445 if (!stringi_set_is_empty (&strings))
4447 const char *example = stringi_set_node_get_string (
4448 stringi_set_first (&strings));
4449 msg (SE, ngettext ("STRINGS specified a variable %s, but no variable "
4450 "with that name was found on SAVE.",
4451 "STRINGS specified %2$zu variables, including %1$s, "
4452 "whose names were not found on SAVE.",
4453 stringi_set_count (&strings)),
4454 example, stringi_set_count (&strings));
4457 stringi_set_destroy (&strings);
4458 string_array_destroy (&names);
4462 gsl_matrix_free (m);
4467 struct casewriter *writer = any_writer_open (save->outfile, dict);
4470 gsl_matrix_free (m);
4475 const struct caseproto *proto = dict_get_proto (dict);
4476 for (size_t y = 0; y < m->size1; y++)
4478 struct ccase *c = case_create (proto);
4479 for (size_t x = 0; x < m->size2; x++)
4481 double d = gsl_matrix_get (m, y, x);
4482 int width = caseproto_get_width (proto, x);
4483 union value *value = case_data_rw_idx (c, x);
4487 memcpy (value->s, &d, width);
4489 casewriter_write (writer, c);
4491 casewriter_destroy (writer);
4493 gsl_matrix_free (m);
4497 static struct matrix_cmd *
4498 matrix_parse_read (struct matrix_state *s)
4500 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4501 *cmd = (struct matrix_cmd) {
4503 .read = { .format = FMT_F },
4506 struct file_handle *fh = NULL;
4507 char *encoding = NULL;
4508 struct read_command *read = &cmd->read;
4509 read->dst = matrix_lvalue_parse (s);
4514 int repetitions = 0;
4515 int record_width = 0;
4516 bool seen_format = false;
4517 while (lex_match (s->lexer, T_SLASH))
4519 if (lex_match_id (s->lexer, "FILE"))
4521 lex_match (s->lexer, T_EQUALS);
4524 fh = fh_parse (s->lexer, FH_REF_FILE, NULL);
4528 else if (lex_match_id (s->lexer, "ENCODING"))
4530 lex_match (s->lexer, T_EQUALS);
4531 if (!lex_force_string (s->lexer))
4535 encoding = ss_xstrdup (lex_tokss (s->lexer));
4539 else if (lex_match_id (s->lexer, "FIELD"))
4541 lex_match (s->lexer, T_EQUALS);
4543 if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX))
4545 read->c1 = lex_integer (s->lexer);
4547 if (!lex_force_match (s->lexer, T_TO)
4548 || !lex_force_int_range (s->lexer, "TO", read->c1, INT_MAX))
4550 read->c2 = lex_integer (s->lexer) + 1;
4553 record_width = read->c2 - read->c1;
4554 if (lex_match (s->lexer, T_BY))
4556 if (!lex_force_int_range (s->lexer, "BY", 1,
4557 read->c2 - read->c1))
4559 by = lex_integer (s->lexer);
4562 if (record_width % by)
4564 msg (SE, _("BY %d does not evenly divide record width %d."),
4572 else if (lex_match_id (s->lexer, "SIZE"))
4574 lex_match (s->lexer, T_EQUALS);
4575 read->size = matrix_parse_exp (s);
4579 else if (lex_match_id (s->lexer, "MODE"))
4581 lex_match (s->lexer, T_EQUALS);
4582 if (lex_match_id (s->lexer, "RECTANGULAR"))
4583 read->symmetric = false;
4584 else if (lex_match_id (s->lexer, "SYMMETRIC"))
4585 read->symmetric = true;
4588 lex_error_expecting (s->lexer, "RECTANGULAR", "SYMMETRIC");
4592 else if (lex_match_id (s->lexer, "REREAD"))
4593 read->reread = true;
4594 else if (lex_match_id (s->lexer, "FORMAT"))
4598 lex_sbc_only_once ("FORMAT");
4603 lex_match (s->lexer, T_EQUALS);
4605 if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer))
4608 const char *p = lex_tokcstr (s->lexer);
4609 if (c_isdigit (p[0]))
4611 repetitions = atoi (p);
4612 p += strspn (p, "0123456789");
4613 if (!fmt_from_name (p, &read->format))
4615 lex_error (s->lexer, _("Unknown format %s."), p);
4620 else if (!fmt_from_name (p, &read->format))
4622 struct fmt_spec format;
4623 if (!parse_format_specifier (s->lexer, &format))
4625 read->format = format.type;
4632 lex_error_expecting (s->lexer, "FILE", "FIELD", "MODE",
4633 "REREAD", "FORMAT");
4640 lex_sbc_missing ("FIELD");
4644 if (!read->dst->n_indexes && !read->size)
4646 msg (SE, _("SIZE is required for reading data into a full matrix "
4647 "(as opposed to a submatrix)."));
4653 if (s->prev_read_file)
4654 fh = fh_ref (s->prev_read_file);
4657 lex_sbc_missing ("FILE");
4661 fh_unref (s->prev_read_file);
4662 s->prev_read_file = fh_ref (fh);
4664 read->rf = read_file_create (s, fh);
4667 free (read->rf->encoding);
4668 read->rf->encoding = encoding;
4672 /* Field width may be specified in multiple ways:
4675 2. The format on FORMAT.
4676 3. The repetition factor on FORMAT.
4678 (2) and (3) are mutually exclusive.
4680 If more than one of these is present, they must agree. If none of them is
4681 present, then free-field format is used.
4683 if (repetitions > record_width)
4685 msg (SE, _("%d repetitions cannot fit in record width %d."),
4686 repetitions, record_width);
4689 int w = (repetitions ? record_width / repetitions
4695 msg (SE, _("FORMAT specifies %d repetitions with record width %d, "
4696 "which implies field width %d, "
4697 "but BY specifies field width %d."),
4698 repetitions, record_width, w, by);
4700 msg (SE, _("FORMAT specifies field width %d but BY specifies %d."),
4708 matrix_cmd_destroy (cmd);
4714 matrix_read_set_field (struct read_command *read, struct dfm_reader *reader,
4715 gsl_matrix *m, struct substring p, size_t y, size_t x)
4717 const char *input_encoding = dfm_reader_get_encoding (reader);
4719 char *error = data_in (p, input_encoding, read->format,
4720 settings_get_fmt_settings (), &v, 0, NULL);
4721 /* XXX report error if value is missing */
4723 msg (SW, _("GET parse error (%.*s): %s"), (int) p.length, p.string, error);
4726 gsl_matrix_set (m, y, x, v.f);
4727 if (read->symmetric && x != y)
4728 gsl_matrix_set (m, x, y, v.f);
4733 matrix_read_line (struct read_command *read, struct dfm_reader *reader,
4734 struct substring *line)
4736 if (dfm_eof (reader))
4738 msg (SE, _("Unexpected end of file reading matrix data."));
4741 dfm_expand_tabs (reader);
4742 *line = ss_substr (dfm_get_record (reader),
4743 read->c1 - 1, read->c2 - read->c1);
4748 matrix_read (struct read_command *read, struct dfm_reader *reader,
4751 for (size_t y = 0; y < m->size1; y++)
4753 size_t nx = read->symmetric ? y + 1 : m->size2;
4755 struct substring line = ss_empty ();
4756 for (size_t x = 0; x < nx; x++)
4763 ss_ltrim (&line, ss_cstr (" ,"));
4764 if (!ss_is_empty (line))
4766 if (!matrix_read_line (read, reader, &line))
4768 dfm_forward_record (reader);
4771 ss_get_bytes (&line, ss_cspan (line, ss_cstr (" ,")), &p);
4775 if (!matrix_read_line (read, reader, &line))
4777 size_t fields_per_line = (read->c2 - read->c1) / read->w;
4778 int f = x % fields_per_line;
4779 if (f == fields_per_line - 1)
4780 dfm_forward_record (reader);
4782 p = ss_substr (line, read->w * f, read->w);
4785 matrix_read_set_field (read, reader, m, p, y, x);
4789 dfm_forward_record (reader);
4792 ss_ltrim (&line, ss_cstr (" ,"));
4793 if (!ss_is_empty (line))
4794 msg (SW, _("Trailing garbage on line \"%.*s\""),
4795 (int) line.length, line.string);
4801 matrix_cmd_execute_read (struct read_command *read)
4803 struct index_vector iv0, iv1;
4804 if (!matrix_lvalue_evaluate (read->dst, &iv0, &iv1))
4807 size_t size[2] = { SIZE_MAX, SIZE_MAX };
4810 gsl_matrix *m = matrix_expr_evaluate (read->size);
4816 msg (SE, _("SIZE must evaluate to a scalar or a 2-element vector"));
4817 gsl_matrix_free (m);
4823 gsl_vector v = to_vector (m);
4827 d[0] = gsl_vector_get (&v, 0);
4830 else if (v.size == 2)
4832 d[0] = gsl_vector_get (&v, 0);
4833 d[1] = gsl_vector_get (&v, 1);
4837 msg (SE, _("SIZE must evaluate to a scalar or a 2-element vector"));
4838 gsl_matrix_free (m);
4843 gsl_matrix_free (m);
4845 if (d[0] < 0 || d[0] > SIZE_MAX || d[1] < 0 || d[1] > SIZE_MAX)
4847 msg (SE, _("SIZE (%g,%g) is outside valid range."), d[0], d[1]);
4857 if (read->dst->n_indexes)
4859 size_t submatrix_size[2];
4860 if (read->dst->n_indexes == 2)
4862 submatrix_size[0] = iv0.n;
4863 submatrix_size[1] = iv1.n;
4865 else if (read->dst->var->value->size1 == 1)
4867 submatrix_size[0] = 1;
4868 submatrix_size[1] = iv0.n;
4872 submatrix_size[0] = iv0.n;
4873 submatrix_size[1] = 1;
4878 if (size[0] != submatrix_size[0] || size[1] != submatrix_size[1])
4880 msg (SE, _("SIZE (%zu,%zu) differs from submatrix dimensions "
4883 submatrix_size[0], submatrix_size[1]);
4891 size[0] = submatrix_size[0];
4892 size[1] = submatrix_size[1];
4896 struct dfm_reader *reader = read_file_open (read->rf);
4898 dfm_reread_record (reader, 1);
4900 if (read->symmetric && size[0] != size[1])
4902 msg (SE, _("Cannot read matrix with non-square dimensions (%zu,%zu) "
4903 "using READ with MODE=SYMMETRIC."),
4909 gsl_matrix *tmp = gsl_matrix_calloc (size[0], size[1]);
4910 matrix_read (read, reader, tmp);
4911 matrix_lvalue_assign (read->dst, &iv0, &iv1, tmp);
4914 static struct matrix_cmd *
4915 matrix_parse_write (struct matrix_state *s)
4917 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4918 *cmd = (struct matrix_cmd) {
4920 .write = { .format = FMT_F },
4923 struct write_command *write = &cmd->write;
4924 write->expression = matrix_parse_exp (s);
4925 if (!write->expression)
4929 int repetitions = 0;
4930 int record_width = 0;
4931 bool seen_format = false;
4932 while (lex_match (s->lexer, T_SLASH))
4934 if (lex_match_id (s->lexer, "OUTFILE"))
4936 lex_match (s->lexer, T_EQUALS);
4938 fh_unref (write->outfile);
4939 write->outfile = fh_parse (s->lexer, FH_REF_FILE, NULL);
4940 if (!write->outfile)
4943 else if (lex_match_id (s->lexer, "ENCODING"))
4945 lex_match (s->lexer, T_EQUALS);
4946 if (!lex_force_string (s->lexer))
4949 free (write->encoding);
4950 write->encoding = ss_xstrdup (lex_tokss (s->lexer));
4954 else if (lex_match_id (s->lexer, "FIELD"))
4956 lex_match (s->lexer, T_EQUALS);
4958 if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX))
4960 write->c1 = lex_integer (s->lexer);
4962 if (!lex_force_match (s->lexer, T_TO)
4963 || !lex_force_int_range (s->lexer, "TO", write->c1, INT_MAX))
4965 write->c2 = lex_integer (s->lexer) + 1;
4968 record_width = write->c2 - write->c1;
4969 if (lex_match (s->lexer, T_BY))
4971 if (!lex_force_int_range (s->lexer, "BY", 1,
4972 write->c2 - write->c1))
4974 by = lex_integer (s->lexer);
4977 if (record_width % by)
4979 msg (SE, _("BY %d does not evenly divide record width %d."),
4987 else if (lex_match_id (s->lexer, "MODE"))
4989 lex_match (s->lexer, T_EQUALS);
4990 if (lex_match_id (s->lexer, "RECTANGULAR"))
4991 write->triangular = false;
4992 else if (lex_match_id (s->lexer, "TRIANGULAR"))
4993 write->triangular = true;
4996 lex_error_expecting (s->lexer, "RECTANGULAR", "TRIANGULAR");
5000 else if (lex_match_id (s->lexer, "HOLD"))
5002 else if (lex_match_id (s->lexer, "FORMAT"))
5006 lex_sbc_only_once ("FORMAT");
5011 lex_match (s->lexer, T_EQUALS);
5013 if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer))
5016 const char *p = lex_tokcstr (s->lexer);
5017 if (c_isdigit (p[0]))
5019 repetitions = atoi (p);
5020 p += strspn (p, "0123456789");
5021 if (!fmt_from_name (p, &write->format))
5023 lex_error (s->lexer, _("Unknown format %s."), p);
5028 else if (!fmt_from_name (p, &write->format))
5030 struct fmt_spec format;
5031 if (!parse_format_specifier (s->lexer, &format))
5033 write->format = format.type;
5034 write->w = format.w;
5035 write->d = format.d;
5040 lex_error_expecting (s->lexer, "OUTFILE", "FIELD", "MODE",
5048 lex_sbc_missing ("FIELD");
5052 if (!write->outfile)
5054 if (s->prev_write_outfile)
5055 write->outfile = fh_ref (s->prev_write_outfile);
5058 lex_sbc_missing ("OUTFILE");
5062 fh_unref (s->prev_write_outfile);
5063 s->prev_write_outfile = fh_ref (write->outfile);
5065 /* Field width may be specified in multiple ways:
5068 2. The format on FORMAT.
5069 3. The repetition factor on FORMAT.
5071 (2) and (3) are mutually exclusive.
5073 If more than one of these is present, they must agree. If none of them is
5074 present, then free-field format is used.
5076 if (repetitions > record_width)
5078 msg (SE, _("%d repetitions cannot fit in record width %d."),
5079 repetitions, record_width);
5082 int w = (repetitions ? record_width / repetitions
5083 : write->w ? write->w
5088 msg (SE, _("FORMAT specifies %d repetitions with record width %d, "
5089 "which implies field width %d, "
5090 "but BY specifies field width %d."),
5091 repetitions, record_width, w, by);
5093 msg (SE, _("FORMAT specifies field width %d but BY specifies %d."),
5101 matrix_cmd_destroy (cmd);
5106 matrix_cmd_execute_write (struct write_command *write)
5108 gsl_matrix *m = matrix_expr_evaluate (write->expression);
5112 if (write->triangular && m->size1 != m->size2)
5114 msg (SE, _("WRITE with MODE=TRIANGULAR requires a square matrix but "
5115 "the matrix to be written has dimensions (%zu,%zu)."),
5116 m->size1, m->size2);
5117 gsl_matrix_free (m);
5121 struct dfm_writer *writer = dfm_open_writer (write->outfile, write->encoding);
5124 gsl_matrix_free (m);
5128 const struct fmt_settings *settings = settings_get_fmt_settings ();
5129 struct fmt_spec format = {
5130 .type = write->format,
5131 .w = write->w ? write->w : 40,
5134 struct u8_line line = U8_LINE_INITIALIZER;
5135 for (size_t y = 0; y < m->size1; y++)
5137 size_t nx = write->triangular ? y + 1 : m->size2;
5139 for (size_t x = 0; x < nx; x++)
5141 /* XXX string values */
5142 union value v = { .f = gsl_matrix_get (m, y, x) };
5144 ? data_out (&v, NULL, &format, settings)
5145 : data_out_stretchy (&v, NULL, &format, settings, NULL));
5146 size_t len = strlen (s);
5147 int width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
5148 if (width + x0 > write->c2)
5150 dfm_put_record_utf8 (writer, line.s.ss.string, line.s.ss.length);
5151 u8_line_clear (&line);
5154 u8_line_put (&line, x0, x0 + width, s, len);
5157 x0 += write->w ? write->w : width + 1;
5160 dfm_put_record_utf8 (writer, line.s.ss.string, line.s.ss.length);
5161 u8_line_clear (&line);
5163 u8_line_destroy (&line);
5164 dfm_close_writer (writer);
5166 gsl_matrix_free (m);
5169 static struct matrix_cmd *
5170 matrix_parse_get (struct matrix_state *s)
5172 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5173 *cmd = (struct matrix_cmd) {
5176 .user = { .treatment = MGET_ERROR },
5177 .system = { .treatment = MGET_ERROR },
5181 struct get_command *get = &cmd->get;
5182 get->dst = matrix_lvalue_parse (s);
5186 while (lex_match (s->lexer, T_SLASH))
5188 if (lex_match_id (s->lexer, "FILE"))
5190 if (get->variables.n)
5192 lex_error (s->lexer, _("FILE must precede VARIABLES"));
5195 lex_match (s->lexer, T_EQUALS);
5197 fh_unref (get->file);
5198 get->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
5202 else if (lex_match_id (s->lexer, "ENCODING"))
5204 if (get->variables.n)
5206 lex_error (s->lexer, _("ENCODING must precede VARIABLES"));
5209 lex_match (s->lexer, T_EQUALS);
5210 if (!lex_force_string (s->lexer))
5213 free (get->encoding);
5214 get->encoding = ss_xstrdup (lex_tokss (s->lexer));
5218 else if (lex_match_id (s->lexer, "VARIABLES"))
5220 lex_match (s->lexer, T_EQUALS);
5222 struct dictionary *dict = NULL;
5225 dict = dataset_dict (s->dataset);
5226 if (dict_get_var_cnt (dict) == 0)
5228 lex_error (s->lexer, _("GET cannot read empty active file."));
5234 struct casereader *reader = any_reader_open_and_decode (
5235 get->file, get->encoding, &dict, NULL);
5238 casereader_destroy (reader);
5241 struct variable **vars;
5243 bool ok = parse_variables (s->lexer, dict, &vars, &n_vars,
5244 PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH);
5251 string_array_clear (&get->variables);
5252 for (size_t i = 0; i < n_vars; i++)
5253 string_array_append (&get->variables, var_get_name (vars[i]));
5257 else if (lex_match_id (s->lexer, "NAMES"))
5259 lex_match (s->lexer, T_EQUALS);
5260 if (!lex_force_id (s->lexer))
5263 struct substring name = lex_tokss (s->lexer);
5264 get->names = matrix_var_lookup (s, name);
5266 get->names = matrix_var_create (s, name);
5269 else if (lex_match_id (s->lexer, "MISSING"))
5271 lex_match (s->lexer, T_EQUALS);
5272 if (lex_match_id (s->lexer, "ACCEPT"))
5273 get->user.treatment = MGET_ACCEPT;
5274 else if (lex_match_id (s->lexer, "OMIT"))
5275 get->user.treatment = MGET_OMIT;
5276 else if (lex_is_number (s->lexer))
5278 get->user.treatment = MGET_RECODE;
5279 get->user.substitute = lex_number (s->lexer);
5284 lex_error (s->lexer, NULL);
5288 else if (lex_match_id (s->lexer, "SYSMIS"))
5290 lex_match (s->lexer, T_EQUALS);
5291 if (lex_match_id (s->lexer, "OMIT"))
5292 get->user.treatment = MGET_OMIT;
5293 else if (lex_is_number (s->lexer))
5295 get->user.treatment = MGET_RECODE;
5296 get->user.substitute = lex_number (s->lexer);
5301 lex_error (s->lexer, NULL);
5307 lex_error_expecting (s->lexer, "FILE", "VARIABLES", "NAMES",
5308 "MISSING", "SYSMIS");
5315 matrix_cmd_destroy (cmd);
5320 matrix_cmd_execute_get (struct get_command *get)
5322 assert (get->file); /* XXX */
5324 struct dictionary *dict;
5325 struct casereader *reader = any_reader_open_and_decode (
5326 get->file, get->encoding, &dict, NULL);
5330 const struct variable **vars = xnmalloc (
5331 get->variables.n ? get->variables.n : dict_get_var_cnt (dict),
5335 if (get->variables.n)
5337 for (size_t i = 0; i < get->variables.n; i++)
5339 const char *name = get->variables.strings[i];
5340 const struct variable *var = dict_lookup_var (dict, name);
5343 msg (SE, _("GET: Data file does not contain variable %s."),
5349 if (!var_is_numeric (var))
5351 msg (SE, _("GET: Variable %s is not numeric."), name);
5356 vars[n_vars++] = var;
5361 for (size_t i = 0; i < dict_get_var_cnt (dict); i++)
5363 const struct variable *var = dict_get_var (dict, i);
5364 if (!var_is_numeric (var))
5366 msg (SE, _("GET: Variable %s is not numeric."),
5367 var_get_name (var));
5372 vars[n_vars++] = var;
5377 gsl_matrix *m = gsl_matrix_alloc (4, n_vars);
5378 long long int casenum = 1;
5380 for (struct ccase *c = casereader_read (reader); c;
5381 c = casereader_read (reader), casenum++)
5383 if (n_rows >= m->size1)
5385 gsl_matrix *p = gsl_matrix_alloc (m->size1 * 2, n_vars);
5386 for (size_t y = 0; y < n_rows; y++)
5387 for (size_t x = 0; x < n_vars; x++)
5388 gsl_matrix_set (p, y, x, gsl_matrix_get (m, y, x));
5389 gsl_matrix_free (m);
5394 for (size_t x = 0; x < n_vars; x++)
5396 const struct variable *var = vars[x];
5397 double d = case_num (c, var);
5400 if (get->system.treatment == MGET_RECODE)
5401 d = get->system.substitute;
5402 else if (get->system.treatment == MGET_OMIT)
5406 msg (SE, _("GET: Variable %s in case %lld "
5407 "is system-missing."),
5408 var_get_name (var), casenum);
5412 else if (var_is_num_missing (var, d, MV_USER))
5414 if (get->user.treatment == MGET_RECODE)
5415 d = get->user.substitute;
5416 else if (get->user.treatment == MGET_OMIT)
5418 else if (get->user.treatment != MGET_ACCEPT)
5420 msg (SE, _("GET: Variable %s in case %lld has user-missing "
5422 var_get_name (var), casenum, d);
5426 gsl_matrix_set (m, n_rows, x, d);
5434 casereader_destroy (reader);
5438 matrix_lvalue_evaluate_and_assign (get->dst, m);
5441 gsl_matrix_free (m);
5447 match_rowtype (struct lexer *lexer)
5449 static const char *rowtypes[] = {
5450 "COV", "CORR", "MEAN", "STDDEV", "N", "COUNT"
5452 size_t n_rowtypes = sizeof rowtypes / sizeof *rowtypes;
5454 for (size_t i = 0; i < n_rowtypes; i++)
5455 if (lex_match_id (lexer, rowtypes[i]))
5458 lex_error_expecting_array (lexer, rowtypes, n_rowtypes);
5463 parse_var_names (struct lexer *lexer, struct string_array *sa)
5465 lex_match (lexer, T_EQUALS);
5467 string_array_clear (sa);
5469 struct dictionary *dict = dict_create (get_default_encoding ());
5470 dict_create_var_assert (dict, "ROWTYPE_", 8);
5471 dict_create_var_assert (dict, "VARNAME_", 8);
5474 bool ok = parse_DATA_LIST_vars (lexer, dict, &names, &n_names,
5475 PV_NO_DUPLICATE | PV_NO_SCRATCH);
5480 string_array_clear (sa);
5481 sa->strings = names;
5482 sa->n = sa->allocated = n_names;
5488 msave_common_uninit (struct msave_common *common)
5492 fh_unref (common->outfile);
5493 string_array_destroy (&common->variables);
5494 string_array_destroy (&common->fnames);
5495 string_array_destroy (&common->snames);
5500 compare_variables (const char *keyword,
5501 const struct string_array *new,
5502 const struct string_array *old)
5508 msg (SE, _("%s may only be specified on MSAVE if it was specified "
5509 "on the first MSAVE within MATRIX."), keyword);
5512 else if (!string_array_equal_case (old, new))
5514 msg (SE, _("%s must specify the same variables each time within "
5515 "a given MATRIX."), keyword);
5522 static struct matrix_cmd *
5523 matrix_parse_msave (struct matrix_state *s)
5525 struct msave_common common = { .outfile = NULL };
5526 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5527 *cmd = (struct matrix_cmd) { .type = MCMD_MSAVE, .msave = { .expr = NULL } };
5529 struct msave_command *msave = &cmd->msave;
5530 if (lex_token (s->lexer) == T_ID)
5531 msave->varname_ = ss_xstrdup (lex_tokss (s->lexer));
5532 msave->expr = matrix_parse_exp (s);
5536 while (lex_match (s->lexer, T_SLASH))
5538 if (lex_match_id (s->lexer, "TYPE"))
5540 lex_match (s->lexer, T_EQUALS);
5542 msave->rowtype = match_rowtype (s->lexer);
5543 if (!msave->rowtype)
5546 else if (lex_match_id (s->lexer, "OUTFILE"))
5548 lex_match (s->lexer, T_EQUALS);
5550 fh_unref (common.outfile);
5551 common.outfile = fh_parse (s->lexer, FH_REF_FILE, NULL);
5552 if (!common.outfile)
5555 else if (lex_match_id (s->lexer, "VARIABLES"))
5557 if (!parse_var_names (s->lexer, &common.variables))
5560 else if (lex_match_id (s->lexer, "FNAMES"))
5562 if (!parse_var_names (s->lexer, &common.fnames))
5565 else if (lex_match_id (s->lexer, "SNAMES"))
5567 if (!parse_var_names (s->lexer, &common.snames))
5570 else if (lex_match_id (s->lexer, "SPLIT"))
5572 lex_match (s->lexer, T_EQUALS);
5574 matrix_expr_destroy (msave->splits);
5575 msave->splits = matrix_parse_exp (s);
5579 else if (lex_match_id (s->lexer, "FACTOR"))
5581 lex_match (s->lexer, T_EQUALS);
5583 matrix_expr_destroy (msave->factors);
5584 msave->factors = matrix_parse_exp (s);
5585 if (!msave->factors)
5590 lex_error_expecting (s->lexer, "TYPE", "OUTFILE", "VARIABLES",
5591 "FNAMES", "SNAMES", "SPLIT", "FACTOR");
5595 if (!msave->rowtype)
5597 lex_sbc_missing ("TYPE");
5600 common.has_splits = msave->splits || common.snames.n;
5601 common.has_factors = msave->factors || common.fnames.n;
5603 struct msave_common *c = s->common ? s->common : &common;
5604 if (c->fnames.n && !msave->factors)
5606 msg (SE, _("FNAMES requires FACTOR."));
5609 if (c->snames.n && !msave->splits)
5611 msg (SE, _("SNAMES requires SPLIT."));
5614 if (c->has_factors && !common.has_factors)
5616 msg (SE, _("%s is required because it was present on the first "
5617 "MSAVE in this MATRIX command."), "FACTOR");
5620 if (c->has_splits && !common.has_splits)
5622 msg (SE, _("%s is required because it was present on the first "
5623 "MSAVE in this MATRIX command."), "SPLIT");
5629 if (!common.outfile)
5631 lex_sbc_missing ("OUTFILE");
5634 s->common = xmemdup (&common, sizeof common);
5640 bool same = common.outfile == s->common->outfile;
5641 fh_unref (common.outfile);
5644 msg (SE, _("OUTFILE must name the same file on each MSAVE "
5645 "within a single MATRIX command."));
5649 if (!compare_variables ("VARIABLES",
5650 &common.variables, &s->common->variables)
5651 || !compare_variables ("FNAMES", &common.fnames, &s->common->fnames)
5652 || !compare_variables ("SNAMES", &common.snames, &s->common->snames))
5654 msave_common_uninit (&common);
5656 msave->common = s->common;
5657 if (!msave->varname_)
5658 msave->varname_ = xasprintf ("MAT%zu", ++s->common->n_varnames);
5662 msave_common_uninit (&common);
5663 matrix_cmd_destroy (cmd);
5668 matrix_expr_evaluate_vector (struct matrix_expr *e, const char *name)
5670 gsl_matrix *m = matrix_expr_evaluate (e);
5676 msg (SE, _("%s expression must evaluate to vector, not a matrix with "
5677 "dimensions (%zu,%zu)."),
5678 name, m->size1, m->size2);
5679 gsl_matrix_free (m);
5683 return matrix_to_vector (m);
5687 msave_add_vars (struct dictionary *d, const struct string_array *vars)
5689 for (size_t i = 0; i < vars->n; i++)
5690 if (!dict_create_var (d, vars->strings[i], 0))
5691 return vars->strings[i];
5695 static struct dictionary *
5696 msave_create_dict (const struct msave_common *common)
5698 struct dictionary *dict = dict_create (get_default_encoding ());
5700 const char *dup_split = msave_add_vars (dict, &common->snames);
5703 msg (SE, _("Duplicate SPLIT variable name %s."), dup_split);
5707 dict_create_var_assert (dict, "ROWTYPE_", 8);
5709 const char *dup_factor = msave_add_vars (dict, &common->fnames);
5712 msg (SE, _("Duplicate or invalid FACTOR variable name %s."), dup_factor);
5716 dict_create_var_assert (dict, "VARNAME_", 8);
5718 const char *dup_var = msave_add_vars (dict, &common->variables);
5721 msg (SE, _("Duplicate or invalid variable name %s."), dup_var);
5733 matrix_cmd_execute_msave (struct msave_command *msave)
5735 struct msave_common *common = msave->common;
5736 gsl_matrix *m = NULL;
5737 gsl_vector *factors = NULL;
5738 gsl_vector *splits = NULL;
5740 m = matrix_expr_evaluate (msave->expr);
5744 if (!common->variables.n)
5745 for (size_t i = 0; i < m->size2; i++)
5746 string_array_append_nocopy (&common->variables,
5747 xasprintf ("COL%zu", i + 1));
5749 if (m->size2 != common->variables.n)
5751 msg (SE, _("Matrix on MSAVE has %zu columns instead of required %zu."),
5752 m->size2, common->variables.n);
5758 factors = matrix_expr_evaluate_vector (msave->factors, "FACTOR");
5762 if (!common->fnames.n)
5763 for (size_t i = 0; i < factors->size; i++)
5764 string_array_append_nocopy (&common->fnames,
5765 xasprintf ("FAC%zu", i + 1));
5767 if (factors->size != common->fnames.n)
5769 msg (SE, _("There are %zu factor variables, "
5770 "but %zu split values were supplied."),
5771 common->fnames.n, factors->size);
5778 splits = matrix_expr_evaluate_vector (msave->splits, "SPLIT");
5782 if (!common->fnames.n)
5783 for (size_t i = 0; i < splits->size; i++)
5784 string_array_append_nocopy (&common->fnames,
5785 xasprintf ("SPL%zu", i + 1));
5787 if (splits->size != common->fnames.n)
5789 msg (SE, _("There are %zu split variables, "
5790 "but %zu split values were supplied."),
5791 common->fnames.n, splits->size);
5796 if (!common->writer)
5798 struct dictionary *dict = msave_create_dict (common);
5802 common->writer = any_writer_open (common->outfile, dict);
5803 if (!common->writer)
5809 common->dict = dict;
5812 for (size_t y = 0; y < m->size1; y++)
5814 struct ccase *c = case_create (dict_get_proto (common->dict));
5817 /* Split variables */
5819 for (size_t i = 0; i < splits->size; i++)
5820 case_data_rw_idx (c, idx++)->f = gsl_vector_get (splits, i);
5823 buf_copy_str_rpad (CHAR_CAST (char *, case_data_rw_idx (c, idx++)->s), 8,
5824 msave->rowtype, ' ');
5828 for (size_t i = 0; i < factors->size; i++)
5829 *case_num_rw_idx (c, idx++) = gsl_vector_get (factors, i);
5832 buf_copy_str_rpad (CHAR_CAST (char *, case_data_rw_idx (c, idx++)->s), 8,
5833 msave->varname_, ' ');
5835 /* Continuous variables. */
5836 for (size_t x = 0; x < m->size2; x++)
5837 case_data_rw_idx (c, idx++)->f = gsl_matrix_get (m, y, x);
5838 casewriter_write (common->writer, c);
5842 gsl_matrix_free (m);
5843 gsl_vector_free (factors);
5844 gsl_vector_free (splits);
5847 static struct matrix_cmd *
5848 matrix_parse_mget (struct matrix_state *s)
5850 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5851 *cmd = (struct matrix_cmd) { .type = MCMD_MGET, .mget = { .state = s } };
5853 struct mget_command *mget = &cmd->mget;
5857 if (lex_match_id (s->lexer, "FILE"))
5859 lex_match (s->lexer, T_EQUALS);
5861 fh_unref (mget->file);
5862 mget->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
5866 else if (lex_match_id (s->lexer, "TYPE"))
5868 lex_match (s->lexer, T_EQUALS);
5869 while (lex_token (s->lexer) != T_SLASH
5870 && lex_token (s->lexer) != T_ENDCMD)
5872 const char *rowtype = match_rowtype (s->lexer);
5876 stringi_set_insert (&mget->rowtypes, rowtype);
5881 lex_error_expecting (s->lexer, "FILE", "TYPE");
5884 if (lex_token (s->lexer) == T_ENDCMD)
5887 if (!lex_force_match (s->lexer, T_SLASH))
5893 matrix_cmd_destroy (cmd);
5897 static const struct variable *
5898 get_a8_var (const struct dictionary *d, const char *name)
5900 const struct variable *v = dict_lookup_var (d, name);
5903 msg (SE, _("Matrix data file lacks %s variable."), name);
5906 if (var_get_width (v) != 8)
5908 msg (SE, _("%s variable in matrix data file must be "
5909 "8-byte string, but it has width %d."),
5910 name, var_get_width (v));
5917 is_rowtype (const union value *v, const char *rowtype)
5919 struct substring vs = ss_buffer (CHAR_CAST (char *, v->s), 8);
5920 ss_rtrim (&vs, ss_cstr (" "));
5921 return ss_equals_case (vs, ss_cstr (rowtype));
5925 matrix_mget_commit_var (struct ccase **rows, size_t n_rows,
5926 const struct dictionary *d,
5927 const struct variable *rowtype_var,
5928 struct matrix_state *s, size_t si, size_t fi,
5929 size_t cs, size_t cn)
5934 const union value *rowtype_ = case_data (rows[0], rowtype_var);
5935 const char *name_prefix = (is_rowtype (rowtype_, "COV") ? "CV"
5936 : is_rowtype (rowtype_, "CORR") ? "CR"
5937 : is_rowtype (rowtype_, "MEAN") ? "MN"
5938 : is_rowtype (rowtype_, "STDDEV") ? "SD"
5939 : is_rowtype (rowtype_, "N") ? "NC"
5942 struct string name = DS_EMPTY_INITIALIZER;
5943 ds_put_cstr (&name, name_prefix);
5945 ds_put_format (&name, "F%zu", fi);
5947 ds_put_format (&name, "S%zu", si);
5949 struct matrix_var *mv = matrix_var_lookup (s, ds_ss (&name));
5951 mv = matrix_var_create (s, ds_ss (&name));
5954 msg (SW, _("Matrix data file contains variable with existing name %s."),
5959 gsl_matrix *m = gsl_matrix_alloc (n_rows, cn);
5960 size_t n_missing = 0;
5961 for (size_t y = 0; y < n_rows; y++)
5963 for (size_t x = 0; x < cn; x++)
5965 struct variable *var = dict_get_var (d, cs + x);
5966 double value = case_num (rows[y], var);
5967 if (var_is_num_missing (var, value, MV_ANY))
5972 gsl_matrix_set (m, y, x, value);
5977 msg (SE, ngettext ("Matrix data file variable %s contains a missing "
5978 "value, which was treated as zero.",
5979 "Matrix data file variable %s contains %zu missing "
5980 "values, which were treated as zero.", n_missing),
5981 ds_cstr (&name), n_missing);
5986 for (size_t y = 0; y < n_rows; y++)
5987 case_unref (rows[y]);
5991 var_changed (const struct ccase *ca, const struct ccase *cb,
5992 const struct variable *var)
5994 return !value_equal (case_data (ca, var), case_data (cb, var),
5995 var_get_width (var));
5999 vars_changed (const struct ccase *ca, const struct ccase *cb,
6000 const struct dictionary *d,
6001 size_t first_var, size_t n_vars)
6003 for (size_t i = 0; i < n_vars; i++)
6005 const struct variable *v = dict_get_var (d, first_var + i);
6006 if (var_changed (ca, cb, v))
6013 matrix_cmd_execute_mget (struct mget_command *mget)
6015 struct dictionary *d;
6016 struct casereader *r = any_reader_open_and_decode (mget->file, "UTF-8",
6021 const struct variable *rowtype_ = get_a8_var (d, "ROWTYPE_");
6022 const struct variable *varname_ = get_a8_var (d, "VARNAME_");
6023 if (!rowtype_ || !varname_)
6026 if (var_get_dict_index (rowtype_) >= var_get_dict_index (varname_))
6028 msg (SE, _("ROWTYPE_ must precede VARNAME_ in matrix data file."));
6031 if (var_get_dict_index (varname_) + 1 >= dict_get_var_cnt (d))
6033 msg (SE, _("Matrix data file contains no continuous variables."));
6037 for (size_t i = 0; i < dict_get_var_cnt (d); i++)
6039 const struct variable *v = dict_get_var (d, i);
6040 if (v != rowtype_ && v != varname_ && var_get_width (v) != 0)
6043 _("Matrix data file contains unexpected string variable %s."),
6049 /* SPLIT variables. */
6051 size_t sn = var_get_dict_index (rowtype_);
6052 struct ccase *sc = NULL;
6055 /* FACTOR variables. */
6056 size_t fs = var_get_dict_index (rowtype_) + 1;
6057 size_t fn = var_get_dict_index (varname_) - var_get_dict_index (rowtype_) - 1;
6058 struct ccase *fc = NULL;
6061 /* Continuous variables. */
6062 size_t cs = var_get_dict_index (varname_) + 1;
6063 size_t cn = dict_get_var_cnt (d) - cs;
6064 struct ccase *cc = NULL;
6067 struct ccase **rows = NULL;
6068 size_t allocated_rows = 0;
6072 while ((c = casereader_read (r)) != NULL)
6074 bool sd = vars_changed (sc, c, d, ss, sn);
6075 bool fd = sd || vars_changed (fc, c, d, fs, fn);
6076 bool md = fd || !cc || var_changed (cc, c, rowtype_) || var_changed (cc, c, varname_);
6091 matrix_mget_commit_var (rows, n_rows, d, rowtype_,
6092 mget->state, si, fi, cs, cn);
6098 if (n_rows >= allocated_rows)
6099 rows = x2nrealloc (rows, &allocated_rows, sizeof *rows);
6102 matrix_mget_commit_var (rows, n_rows, d, rowtype_,
6103 mget->state, si, fi, cs, cn);
6107 casereader_destroy (r);
6111 matrix_parse_dst_var (struct matrix_state *s, struct matrix_var **varp)
6113 if (!lex_force_id (s->lexer))
6116 *varp = matrix_var_lookup (s, lex_tokss (s->lexer));
6118 *varp = matrix_var_create (s, lex_tokss (s->lexer));
6123 static struct matrix_cmd *
6124 matrix_parse_eigen (struct matrix_state *s)
6126 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6127 *cmd = (struct matrix_cmd) {
6129 .eigen = { .expr = NULL }
6132 struct eigen_command *eigen = &cmd->eigen;
6133 if (!lex_force_match (s->lexer, T_LPAREN))
6135 eigen->expr = matrix_parse_expr (s);
6137 || !lex_force_match (s->lexer, T_COMMA)
6138 || !matrix_parse_dst_var (s, &eigen->evec)
6139 || !lex_force_match (s->lexer, T_COMMA)
6140 || !matrix_parse_dst_var (s, &eigen->eval)
6141 || !lex_force_match (s->lexer, T_RPAREN))
6147 matrix_cmd_destroy (cmd);
6152 matrix_cmd_execute_eigen (struct eigen_command *eigen)
6154 gsl_matrix *A = matrix_expr_evaluate (eigen->expr);
6157 if (!is_symmetric (A))
6159 msg (SE, _("Argument of EIGEN must be symmetric."));
6160 gsl_matrix_free (A);
6164 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc (A->size1);
6165 gsl_matrix *eval = gsl_matrix_alloc (A->size1, 1);
6166 gsl_vector v_eval = to_vector (eval);
6167 gsl_matrix *evec = gsl_matrix_alloc (A->size1, A->size2);
6168 gsl_eigen_symmv (A, &v_eval, evec, w);
6169 gsl_eigen_symmv_free (w);
6171 gsl_eigen_symmv_sort (&v_eval, evec, GSL_EIGEN_SORT_VAL_DESC);
6173 gsl_matrix_free (A);
6175 gsl_matrix_free (eigen->eval->value);
6176 eigen->eval->value = eval;
6178 gsl_matrix_free (eigen->evec->value);
6179 eigen->evec->value = evec;
6182 static struct matrix_cmd *
6183 matrix_parse_setdiag (struct matrix_state *s)
6185 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6186 *cmd = (struct matrix_cmd) {
6187 .type = MCMD_SETDIAG,
6188 .setdiag = { .dst = NULL }
6191 struct setdiag_command *setdiag = &cmd->setdiag;
6192 if (!lex_force_match (s->lexer, T_LPAREN) || !lex_force_id (s->lexer))
6195 setdiag->dst = matrix_var_lookup (s, lex_tokss (s->lexer));
6198 lex_error (s->lexer, _("Unknown variable %s."), lex_tokcstr (s->lexer));
6203 if (!lex_force_match (s->lexer, T_COMMA))
6206 setdiag->expr = matrix_parse_expr (s);
6210 if (!lex_force_match (s->lexer, T_RPAREN))
6216 matrix_cmd_destroy (cmd);
6221 matrix_cmd_execute_setdiag (struct setdiag_command *setdiag)
6223 gsl_matrix *dst = setdiag->dst->value;
6226 msg (SE, _("SETDIAG destination matrix %s is uninitialized."),
6227 setdiag->dst->name);
6231 gsl_matrix *src = matrix_expr_evaluate (setdiag->expr);
6235 size_t n = MIN (dst->size1, dst->size2);
6236 if (is_scalar (src))
6238 double d = to_scalar (src);
6239 for (size_t i = 0; i < n; i++)
6240 gsl_matrix_set (dst, i, i, d);
6242 else if (is_vector (src))
6244 gsl_vector v = to_vector (src);
6245 for (size_t i = 0; i < n && i < v.size; i++)
6246 gsl_matrix_set (dst, i, i, gsl_vector_get (&v, i));
6249 msg (SE, _("SETDIAG argument 2 must be a scalar or a vector but it "
6250 "has dimensions (%zu,%zu)."),
6251 src->size1, src->size2);
6252 gsl_matrix_free (src);
6255 static struct matrix_cmd *
6256 matrix_parse_svd (struct matrix_state *s)
6258 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6259 *cmd = (struct matrix_cmd) {
6261 .svd = { .expr = NULL }
6264 struct svd_command *svd = &cmd->svd;
6265 if (!lex_force_match (s->lexer, T_LPAREN))
6267 svd->expr = matrix_parse_expr (s);
6269 || !lex_force_match (s->lexer, T_COMMA)
6270 || !matrix_parse_dst_var (s, &svd->u)
6271 || !lex_force_match (s->lexer, T_COMMA)
6272 || !matrix_parse_dst_var (s, &svd->s)
6273 || !lex_force_match (s->lexer, T_COMMA)
6274 || !matrix_parse_dst_var (s, &svd->v)
6275 || !lex_force_match (s->lexer, T_RPAREN))
6281 matrix_cmd_destroy (cmd);
6286 matrix_cmd_execute_svd (struct svd_command *svd)
6288 gsl_matrix *m = matrix_expr_evaluate (svd->expr);
6292 if (m->size1 >= m->size2)
6295 gsl_matrix *V = gsl_matrix_alloc (A->size2, A->size2);
6296 gsl_matrix *S = gsl_matrix_calloc (A->size2, A->size2);
6297 gsl_vector Sv = gsl_matrix_diagonal (S).vector;
6298 gsl_vector *work = gsl_vector_alloc (A->size2);
6299 gsl_linalg_SV_decomp (A, V, &Sv, work);
6300 gsl_vector_free (work);
6302 matrix_var_set (svd->u, A);
6303 matrix_var_set (svd->s, S);
6304 matrix_var_set (svd->v, V);
6308 gsl_matrix *At = gsl_matrix_alloc (m->size2, m->size1);
6309 gsl_matrix_transpose_memcpy (At, m);
6310 gsl_matrix_free (m);
6312 gsl_matrix *Vt = gsl_matrix_alloc (At->size2, At->size2);
6313 gsl_matrix *St = gsl_matrix_calloc (At->size2, At->size2);
6314 gsl_vector Stv = gsl_matrix_diagonal (St).vector;
6315 gsl_vector *work = gsl_vector_alloc (At->size2);
6316 gsl_linalg_SV_decomp (At, Vt, &Stv, work);
6317 gsl_vector_free (work);
6319 matrix_var_set (svd->v, At);
6320 matrix_var_set (svd->s, St);
6321 matrix_var_set (svd->u, Vt);
6326 matrix_cmd_execute (struct matrix_cmd *cmd)
6331 matrix_cmd_execute_compute (&cmd->compute);
6335 matrix_cmd_execute_print (&cmd->print);
6339 return matrix_cmd_execute_do_if (&cmd->do_if);
6342 matrix_cmd_execute_loop (&cmd->loop);
6349 matrix_cmd_execute_display (&cmd->display);
6353 matrix_cmd_execute_release (&cmd->release);
6357 matrix_cmd_execute_save (&cmd->save);
6361 matrix_cmd_execute_read (&cmd->read);
6365 matrix_cmd_execute_write (&cmd->write);
6369 matrix_cmd_execute_get (&cmd->get);
6373 matrix_cmd_execute_msave (&cmd->msave);
6377 matrix_cmd_execute_mget (&cmd->mget);
6381 matrix_cmd_execute_eigen (&cmd->eigen);
6385 matrix_cmd_execute_setdiag (&cmd->setdiag);
6389 matrix_cmd_execute_svd (&cmd->svd);
6397 matrix_cmds_uninit (struct matrix_cmds *cmds)
6399 for (size_t i = 0; i < cmds->n; i++)
6400 matrix_cmd_destroy (cmds->commands[i]);
6401 free (cmds->commands);
6405 matrix_cmd_destroy (struct matrix_cmd *cmd)
6413 matrix_lvalue_destroy (cmd->compute.lvalue);
6414 matrix_expr_destroy (cmd->compute.rvalue);
6418 matrix_expr_destroy (cmd->print.expression);
6419 free (cmd->print.title);
6420 print_labels_destroy (cmd->print.rlabels);
6421 print_labels_destroy (cmd->print.clabels);
6425 for (size_t i = 0; i < cmd->do_if.n_clauses; i++)
6427 matrix_expr_destroy (cmd->do_if.clauses[i].condition);
6428 matrix_cmds_uninit (&cmd->do_if.clauses[i].commands);
6430 free (cmd->do_if.clauses);
6434 matrix_expr_destroy (cmd->loop.start);
6435 matrix_expr_destroy (cmd->loop.end);
6436 matrix_expr_destroy (cmd->loop.increment);
6437 matrix_expr_destroy (cmd->loop.top_condition);
6438 matrix_expr_destroy (cmd->loop.bottom_condition);
6439 matrix_cmds_uninit (&cmd->loop.commands);
6449 free (cmd->release.vars);
6453 matrix_expr_destroy (cmd->save.expression);
6454 fh_unref (cmd->save.outfile);
6455 string_array_destroy (cmd->save.variables);
6456 matrix_expr_destroy (cmd->save.names);
6457 stringi_set_destroy (&cmd->save.strings);
6461 matrix_lvalue_destroy (cmd->read.dst);
6462 matrix_expr_destroy (cmd->read.size);
6466 matrix_expr_destroy (cmd->write.expression);
6467 free (cmd->write.encoding);
6471 matrix_lvalue_destroy (cmd->get.dst);
6472 fh_unref (cmd->get.file);
6473 free (cmd->get.encoding);
6474 string_array_destroy (&cmd->get.variables);
6478 free (cmd->msave.varname_);
6479 matrix_expr_destroy (cmd->msave.expr);
6480 matrix_expr_destroy (cmd->msave.factors);
6481 matrix_expr_destroy (cmd->msave.splits);
6485 fh_unref (cmd->mget.file);
6486 stringi_set_destroy (&cmd->mget.rowtypes);
6490 matrix_expr_destroy (cmd->eigen.expr);
6494 matrix_expr_destroy (cmd->setdiag.expr);
6498 matrix_expr_destroy (cmd->svd.expr);
6504 struct matrix_command_name
6507 struct matrix_cmd *(*parse) (struct matrix_state *);
6510 static const struct matrix_command_name *
6511 matrix_parse_command_name (struct lexer *lexer)
6513 static const struct matrix_command_name commands[] = {
6514 { "COMPUTE", matrix_parse_compute },
6515 { "CALL EIGEN", matrix_parse_eigen },
6516 { "CALL SETDIAG", matrix_parse_setdiag },
6517 { "CALL SVD", matrix_parse_svd },
6518 { "PRINT", matrix_parse_print },
6519 { "DO IF", matrix_parse_do_if },
6520 { "LOOP", matrix_parse_loop },
6521 { "BREAK", matrix_parse_break },
6522 { "READ", matrix_parse_read },
6523 { "WRITE", matrix_parse_write },
6524 { "GET", matrix_parse_get },
6525 { "SAVE", matrix_parse_save },
6526 { "MGET", matrix_parse_mget },
6527 { "MSAVE", matrix_parse_msave },
6528 { "DISPLAY", matrix_parse_display },
6529 { "RELEASE", matrix_parse_release },
6531 static size_t n = sizeof commands / sizeof *commands;
6533 for (const struct matrix_command_name *c = commands; c < &commands[n]; c++)
6534 if (lex_match_phrase (lexer, c->name))
6539 static struct matrix_cmd *
6540 matrix_parse_command (struct matrix_state *s)
6542 size_t nesting_level = SIZE_MAX;
6544 struct matrix_cmd *c = NULL;
6545 const struct matrix_command_name *cmd = matrix_parse_command_name (s->lexer);
6547 lex_error (s->lexer, _("Unknown matrix command."));
6548 else if (!cmd->parse)
6549 lex_error (s->lexer, _("Matrix command %s is not yet implemented."),
6553 nesting_level = output_open_group (
6554 group_item_create_nocopy (utf8_to_title (cmd->name),
6555 utf8_to_title (cmd->name)));
6560 lex_end_of_command (s->lexer);
6561 lex_discard_rest_of_command (s->lexer);
6562 if (nesting_level != SIZE_MAX)
6563 output_close_groups (nesting_level);
6569 cmd_matrix (struct lexer *lexer, struct dataset *ds)
6571 if (!lex_force_match (lexer, T_ENDCMD))
6574 struct matrix_state state = {
6575 .session = dataset_session (ds),
6577 .vars = HMAP_INITIALIZER (state.vars),
6582 while (lex_match (lexer, T_ENDCMD))
6584 if (lex_token (lexer) == T_STOP)
6586 msg (SE, _("Unexpected end of input expecting matrix command."));
6590 if (lex_match_phrase (lexer, "END MATRIX"))
6593 struct matrix_cmd *c = matrix_parse_command (&state);
6596 matrix_cmd_execute (c);
6597 matrix_cmd_destroy (c);
6601 struct matrix_var *var, *next;
6602 HMAP_FOR_EACH_SAFE (var, next, struct matrix_var, hmap_node, &state.vars)
6605 gsl_matrix_free (var->value);
6606 hmap_delete (&state.vars, &var->hmap_node);
6609 hmap_destroy (&state.vars);
6610 fh_unref (state.prev_save_outfile);
6611 fh_unref (state.prev_write_outfile);
6614 dict_unref (state.common->dict);
6615 casewriter_destroy (state.common->writer);
6616 free (state.common);
6618 fh_unref (state.prev_read_file);
6619 for (size_t i = 0; i < state.n_read_files; i++)
6620 read_file_destroy (state.read_files[i]);
6621 free (state.read_files);