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 file_handle *file;
102 struct dfm_writer *writer;
108 struct dataset *dataset;
109 struct session *session;
113 struct file_handle *prev_save_outfile;
114 struct msave_common *common;
116 struct file_handle *prev_read_file;
117 struct read_file **read_files;
120 struct file_handle *prev_write_file;
121 struct write_file **write_files;
122 size_t n_write_files;
125 static struct matrix_var *
126 matrix_var_lookup (struct matrix_state *s, struct substring name)
128 struct matrix_var *var;
130 HMAP_FOR_EACH_WITH_HASH (var, struct matrix_var, hmap_node,
131 utf8_hash_case_substring (name, 0), &s->vars)
132 if (!utf8_sscasecmp (ss_cstr (var->name), name))
138 static struct matrix_var *
139 matrix_var_create (struct matrix_state *s, struct substring name)
141 struct matrix_var *var = xmalloc (sizeof *var);
142 *var = (struct matrix_var) { .name = ss_xstrdup (name) };
143 hmap_insert (&s->vars, &var->hmap_node, utf8_hash_case_substring (name, 0));
148 matrix_var_set (struct matrix_var *var, gsl_matrix *value)
150 gsl_matrix_free (var->value);
154 #define MATRIX_FUNCTIONS \
210 enum { m_d_MIN_ARGS = 1, m_d_MAX_ARGS = 1 };
211 enum { m_dd_MIN_ARGS = 2, m_dd_MAX_ARGS = 2 };
212 enum { m_ddd_MIN_ARGS = 3, m_ddd_MAX_ARGS = 3 };
213 enum { m_m_MIN_ARGS = 1, m_m_MAX_ARGS = 1 };
214 enum { m_md_MIN_ARGS = 2, m_md_MAX_ARGS = 2 };
215 enum { m_mdd_MIN_ARGS = 3, m_mdd_MAX_ARGS = 3 };
216 enum { m_mm_MIN_ARGS = 2, m_mm_MAX_ARGS = 2 };
217 enum { m_v_MIN_ARGS = 1, m_v_MAX_ARGS = 1 };
218 enum { d_m_MIN_ARGS = 1, d_m_MAX_ARGS = 1 };
219 enum { m_any_MIN_ARGS = 1, m_any_MAX_ARGS = INT_MAX };
220 enum { IDENT_MIN_ARGS = 1, IDENT_MAX_ARGS = 2 };
222 typedef gsl_matrix *matrix_proto_m_d (double);
223 typedef gsl_matrix *matrix_proto_m_dd (double, double);
224 typedef gsl_matrix *matrix_proto_m_ddd (double, double, double);
225 typedef gsl_matrix *matrix_proto_m_m (gsl_matrix *);
226 typedef gsl_matrix *matrix_proto_m_md (gsl_matrix *, double);
227 typedef gsl_matrix *matrix_proto_m_mdd (gsl_matrix *, double, double);
228 typedef gsl_matrix *matrix_proto_m_mm (gsl_matrix *, gsl_matrix *);
229 typedef gsl_matrix *matrix_proto_m_v (gsl_vector *);
230 typedef double matrix_proto_d_m (gsl_matrix *);
231 typedef gsl_matrix *matrix_proto_m_any (gsl_matrix *[], size_t n);
232 typedef gsl_matrix *matrix_proto_IDENT (double, double);
234 #define F(NAME, PROTOTYPE) static matrix_proto_##PROTOTYPE matrix_eval_##NAME;
238 /* Matrix expressions. */
245 #define F(NAME, PROTOTYPE) MOP_F_##NAME,
249 /* Elementwise and scalar arithmetic. */
250 MOP_NEGATE, /* unary - */
251 MOP_ADD_ELEMS, /* + */
252 MOP_SUB_ELEMS, /* - */
253 MOP_MUL_ELEMS, /* &* */
254 MOP_DIV_ELEMS, /* / and &/ */
255 MOP_EXP_ELEMS, /* &** */
257 MOP_SEQ_BY, /* a:b:c */
259 /* Matrix arithmetic. */
261 MOP_EXP_MAT, /* ** */
278 MOP_PASTE_HORZ, /* a, b, c, ... */
279 MOP_PASTE_VERT, /* a; b; c; ... */
283 MOP_VEC_INDEX, /* x(y) */
284 MOP_VEC_ALL, /* x(:) */
285 MOP_MAT_INDEX, /* x(y,z) */
286 MOP_ROW_INDEX, /* x(y,:) */
287 MOP_COL_INDEX, /* x(:,z) */
294 MOP_EOF, /* EOF('file') */
302 struct matrix_expr **subs;
307 struct matrix_var *variable;
308 struct read_file *eof;
313 matrix_expr_destroy (struct matrix_expr *e)
320 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
351 for (size_t i = 0; i < e->n_subs; i++)
352 matrix_expr_destroy (e->subs[i]);
364 static struct matrix_expr *
365 matrix_expr_create_subs (enum matrix_op op, struct matrix_expr **subs,
368 struct matrix_expr *e = xmalloc (sizeof *e);
369 *e = (struct matrix_expr) {
371 .subs = xmemdup (subs, n_subs * sizeof *subs),
377 static struct matrix_expr *
378 matrix_expr_create_0 (enum matrix_op op)
380 struct matrix_expr *sub;
381 return matrix_expr_create_subs (op, &sub, 0);
384 static struct matrix_expr *
385 matrix_expr_create_1 (enum matrix_op op, struct matrix_expr *sub)
387 return matrix_expr_create_subs (op, &sub, 1);
390 static struct matrix_expr *
391 matrix_expr_create_2 (enum matrix_op op,
392 struct matrix_expr *sub0, struct matrix_expr *sub1)
394 struct matrix_expr *subs[] = { sub0, sub1 };
395 return matrix_expr_create_subs (op, subs, sizeof subs / sizeof *subs);
398 static struct matrix_expr *
399 matrix_expr_create_3 (enum matrix_op op, struct matrix_expr *sub0,
400 struct matrix_expr *sub1, struct matrix_expr *sub2)
402 struct matrix_expr *subs[] = { sub0, sub1, sub2 };
403 return matrix_expr_create_subs (op, subs, sizeof subs / sizeof *subs);
406 static struct matrix_expr *
407 matrix_expr_create_number (double number)
409 struct matrix_expr *e = xmalloc (sizeof *e);
410 *e = (struct matrix_expr) { .op = MOP_NUMBER, .number = number };
414 static struct matrix_expr *matrix_parse_or_xor (struct matrix_state *);
416 static struct matrix_expr *
417 matrix_parse_curly_comma (struct matrix_state *s)
419 struct matrix_expr *lhs = matrix_parse_or_xor (s);
423 while (lex_match (s->lexer, T_COMMA))
425 struct matrix_expr *rhs = matrix_parse_or_xor (s);
428 matrix_expr_destroy (lhs);
431 lhs = matrix_expr_create_2 (MOP_PASTE_HORZ, lhs, rhs);
436 static struct matrix_expr *
437 matrix_parse_curly_semi (struct matrix_state *s)
439 if (lex_token (s->lexer) == T_RCURLY)
440 return matrix_expr_create_0 (MOP_EMPTY);
442 struct matrix_expr *lhs = matrix_parse_curly_comma (s);
446 while (lex_match (s->lexer, T_SEMICOLON))
448 struct matrix_expr *rhs = matrix_parse_curly_comma (s);
451 matrix_expr_destroy (lhs);
454 lhs = matrix_expr_create_2 (MOP_PASTE_VERT, lhs, rhs);
459 #define MATRIX_FOR_ALL_ELEMENTS(D, Y, X, M) \
460 for (size_t Y = 0; Y < (M)->size1; Y++) \
461 for (size_t X = 0; X < (M)->size2; X++) \
462 for (double *D = gsl_matrix_ptr ((M), Y, X); D; D = NULL)
465 is_vector (const gsl_matrix *m)
467 return m->size1 <= 1 || m->size2 <= 1;
471 to_vector (gsl_matrix *m)
473 return (m->size1 == 1
474 ? gsl_matrix_row (m, 0).vector
475 : gsl_matrix_column (m, 0).vector);
480 matrix_eval_ABS (gsl_matrix *m)
482 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
488 matrix_eval_ALL (gsl_matrix *m)
490 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
497 matrix_eval_ANY (gsl_matrix *m)
499 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
506 matrix_eval_ARSIN (gsl_matrix *m)
508 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
514 matrix_eval_ARTAN (gsl_matrix *m)
516 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
522 matrix_eval_BLOCK (gsl_matrix *m[], size_t n)
526 for (size_t i = 0; i < n; i++)
531 gsl_matrix *block = gsl_matrix_calloc (r, c);
533 for (size_t i = 0; i < n; i++)
535 for (size_t y = 0; y < m[i]->size1; y++)
536 for (size_t x = 0; x < m[i]->size2; x++)
537 gsl_matrix_set (block, r + y, c + x, gsl_matrix_get (m[i], y, x));
545 matrix_eval_CHOL (gsl_matrix *m)
547 if (!gsl_linalg_cholesky_decomp1 (m))
549 for (size_t y = 0; y < m->size1; y++)
550 for (size_t x = y + 1; x < m->size2; x++)
551 gsl_matrix_set (m, y, x, gsl_matrix_get (m, x, y));
553 for (size_t y = 0; y < m->size1; y++)
554 for (size_t x = 0; x < y; x++)
555 gsl_matrix_set (m, y, x, 0);
560 msg (SE, _("Input to CHOL function is not positive-definite."));
566 matrix_eval_col_extremum (gsl_matrix *m, bool min)
571 return gsl_matrix_alloc (1, 0);
573 gsl_matrix *cext = gsl_matrix_alloc (1, m->size2);
574 for (size_t x = 0; x < m->size2; x++)
576 double ext = gsl_matrix_get (m, 0, x);
577 for (size_t y = 1; y < m->size1; y++)
579 double value = gsl_matrix_get (m, y, x);
580 if (min ? value < ext : value > ext)
583 gsl_matrix_set (cext, 0, x, ext);
589 matrix_eval_CMAX (gsl_matrix *m)
591 return matrix_eval_col_extremum (m, false);
595 matrix_eval_CMIN (gsl_matrix *m)
597 return matrix_eval_col_extremum (m, true);
601 matrix_eval_COS (gsl_matrix *m)
603 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
609 matrix_eval_col_sum (gsl_matrix *m, bool square)
614 return gsl_matrix_alloc (1, 0);
616 gsl_matrix *result = gsl_matrix_alloc (1, m->size2);
617 for (size_t x = 0; x < m->size2; x++)
620 for (size_t y = 0; y < m->size1; y++)
622 double d = gsl_matrix_get (m, y, x);
623 sum += square ? pow2 (d) : d;
625 gsl_matrix_set (result, 0, x, sum);
631 matrix_eval_CSSQ (gsl_matrix *m)
633 return matrix_eval_col_sum (m, true);
637 matrix_eval_CSUM (gsl_matrix *m)
639 return matrix_eval_col_sum (m, false);
643 compare_double_3way (const void *a_, const void *b_)
645 const double *a = a_;
646 const double *b = b_;
647 return *a < *b ? -1 : *a > *b;
651 matrix_eval_DESIGN (gsl_matrix *m)
653 double *tmp = xmalloc (m->size1 * m->size2 * sizeof *tmp);
654 gsl_matrix m2 = gsl_matrix_view_array (tmp, m->size2, m->size1).matrix;
655 gsl_matrix_transpose_memcpy (&m2, m);
657 for (size_t y = 0; y < m2.size1; y++)
658 qsort (tmp + y * m2.size2, m2.size2, sizeof *tmp, compare_double_3way);
660 size_t *n = xcalloc (m2.size1, sizeof *n);
662 for (size_t i = 0; i < m2.size1; i++)
664 double *row = tmp + m2.size2 * i;
665 for (size_t j = 0; j < m2.size2; )
668 for (k = j + 1; k < m2.size2; k++)
669 if (row[j] != row[k])
671 row[n[i]++] = row[j];
676 msg (MW, _("Column %zu in DESIGN argument has constant value."), i + 1);
681 gsl_matrix *result = gsl_matrix_alloc (m->size1, n_total);
683 for (size_t i = 0; i < m->size2; i++)
688 const double *unique = tmp + m2.size2 * i;
689 for (size_t j = 0; j < n[i]; j++, x++)
691 double value = unique[j];
692 for (size_t y = 0; y < m->size1; y++)
693 gsl_matrix_set (result, y, x, gsl_matrix_get (m, y, i) == value);
704 matrix_eval_DET (gsl_matrix *m)
706 gsl_permutation *p = gsl_permutation_alloc (m->size1);
708 gsl_linalg_LU_decomp (m, p, &signum);
709 gsl_permutation_free (p);
710 return gsl_linalg_LU_det (m, signum);
714 matrix_eval_DIAG (gsl_matrix *m)
716 gsl_matrix *diag = gsl_matrix_alloc (MIN (m->size1, m->size2), 1);
717 for (size_t i = 0; i < diag->size1; i++)
718 gsl_matrix_set (diag, i, 0, gsl_matrix_get (m, i, i));
723 is_symmetric (const gsl_matrix *m)
725 if (m->size1 != m->size2)
728 for (size_t y = 0; y < m->size1; y++)
729 for (size_t x = 0; x < y; x++)
730 if (gsl_matrix_get (m, y, x) != gsl_matrix_get (m, x, y))
737 compare_double_desc (const void *a_, const void *b_)
739 const double *a = a_;
740 const double *b = b_;
741 return *a > *b ? -1 : *a < *b;
745 matrix_eval_EVAL (gsl_matrix *m)
747 if (!is_symmetric (m))
749 msg (SE, _("Argument of EVAL must be symmetric."));
753 gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc (m->size1);
754 gsl_matrix *eval = gsl_matrix_alloc (m->size1, 1);
755 gsl_vector v_eval = to_vector (eval);
756 gsl_eigen_symm (m, &v_eval, w);
757 gsl_eigen_symm_free (w);
759 assert (v_eval.stride == 1);
760 qsort (v_eval.data, v_eval.size, sizeof *v_eval.data, compare_double_desc);
766 matrix_eval_EXP (gsl_matrix *m)
768 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
773 /* From https://gist.github.com/turingbirds/5e99656e08dbe1324c99, where it was
776 Charl Linssen <charl@itfromb.it>
780 matrix_eval_GINV (gsl_matrix *A)
785 gsl_matrix *tmp_mat = NULL;
788 /* libgsl SVD can only handle the case m <= n, so transpose matrix. */
789 tmp_mat = gsl_matrix_alloc (m, n);
790 gsl_matrix_transpose_memcpy (tmp_mat, A);
798 gsl_matrix *V = gsl_matrix_alloc (m, m);
799 gsl_vector *u = gsl_vector_alloc (m);
801 gsl_vector *tmp_vec = gsl_vector_alloc (m);
802 gsl_linalg_SV_decomp (A, V, u, tmp_vec);
803 gsl_vector_free (tmp_vec);
806 gsl_matrix *Sigma_pinv = gsl_matrix_alloc (m, n);
807 gsl_matrix_set_zero (Sigma_pinv);
808 double cutoff = 1e-15 * gsl_vector_max (u);
810 for (size_t i = 0; i < m; ++i)
812 double x = gsl_vector_get (u, i);
813 gsl_matrix_set (Sigma_pinv, i, i, x > cutoff ? 1.0 / x : 0);
816 /* libgsl SVD yields "thin" SVD - pad to full matrix by adding zeros */
817 gsl_matrix *U = gsl_matrix_calloc (n, n);
818 for (size_t i = 0; i < n; i++)
819 for (size_t j = 0; j < m; j++)
820 gsl_matrix_set (U, i, j, gsl_matrix_get (A, i, j));
822 /* two dot products to obtain pseudoinverse */
823 gsl_matrix *tmp_mat2 = gsl_matrix_alloc (m, n);
824 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1., V, Sigma_pinv, 0., tmp_mat2);
829 A_pinv = gsl_matrix_alloc (n, m);
830 gsl_blas_dgemm (CblasNoTrans, CblasTrans, 1., U, tmp_mat2, 0., A_pinv);
834 A_pinv = gsl_matrix_alloc (m, n);
835 gsl_blas_dgemm (CblasNoTrans, CblasTrans, 1., tmp_mat2, U, 0., A_pinv);
838 gsl_matrix_free (tmp_mat);
839 gsl_matrix_free (tmp_mat2);
841 gsl_matrix_free (Sigma_pinv);
855 grade_compare_3way (const void *a_, const void *b_)
857 const struct grade *a = a_;
858 const struct grade *b = b_;
860 return (a->value < b->value ? -1
861 : a->value > b->value ? 1
869 matrix_eval_GRADE (gsl_matrix *m)
871 size_t n = m->size1 * m->size2;
872 struct grade *grades = xmalloc (n * sizeof *grades);
875 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
876 grades[i++] = (struct grade) { .y = y, .x = x, .value = *d };
877 qsort (grades, n, sizeof *grades, grade_compare_3way);
879 for (size_t i = 0; i < n; i++)
880 gsl_matrix_set (m, grades[i].y, grades[i].x, i + 1);
888 dot (gsl_vector *a, gsl_vector *b)
891 for (size_t i = 0; i < a->size; i++)
892 result += gsl_vector_get (a, i) * gsl_vector_get (b, i);
897 norm2 (gsl_vector *v)
900 for (size_t i = 0; i < v->size; i++)
901 result += pow2 (gsl_vector_get (v, i));
908 return sqrt (norm2 (v));
912 matrix_eval_GSCH (gsl_matrix *v)
914 if (v->size2 < v->size1)
916 msg (SE, _("GSCH requires its argument to have at least as many columns "
917 "as rows, but it has dimensions %zu×%zu."),
921 if (!v->size1 || !v->size2)
924 gsl_matrix *u = gsl_matrix_calloc (v->size1, v->size2);
926 for (size_t vx = 0; vx < v->size2; vx++)
928 gsl_vector u_i = gsl_matrix_column (u, ux).vector;
929 gsl_vector v_i = gsl_matrix_column (v, vx).vector;
931 gsl_vector_memcpy (&u_i, &v_i);
932 for (size_t j = 0; j < ux; j++)
934 gsl_vector u_j = gsl_matrix_column (u, j).vector;
935 double scale = dot (&u_j, &u_i) / norm2 (&u_j);
936 for (size_t k = 0; k < u_i.size; k++)
937 gsl_vector_set (&u_i, k, (gsl_vector_get (&u_i, k)
938 - scale * gsl_vector_get (&u_j, k)));
941 double len = norm (&u_i);
944 gsl_vector_scale (&u_i, 1.0 / len);
945 if (++ux >= v->size1)
952 msg (SE, _("%zu×%zu argument to GSCH contains only "
953 "%zu linearly independent columns."),
954 v->size1, v->size2, ux);
964 matrix_eval_IDENT (double s1, double s2)
966 if (s1 < 0 || s1 > SIZE_MAX || s2 < 0 || s2 > SIZE_MAX)
968 msg (SE, _("Arguments to IDENT must be non-negative integers."));
972 gsl_matrix *m = gsl_matrix_alloc (s1, s2);
973 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
979 invert_matrix (gsl_matrix *x)
981 gsl_permutation *p = gsl_permutation_alloc (x->size1);
983 gsl_linalg_LU_decomp (x, p, &signum);
984 gsl_linalg_LU_invx (x, p);
985 gsl_permutation_free (p);
989 matrix_eval_INV (gsl_matrix *m)
996 matrix_eval_KRONEKER (gsl_matrix *a, gsl_matrix *b)
998 gsl_matrix *k = gsl_matrix_alloc (a->size1 * b->size1,
999 a->size2 * b->size2);
1001 for (size_t ar = 0; ar < a->size1; ar++)
1002 for (size_t br = 0; br < b->size1; br++, y++)
1005 for (size_t ac = 0; ac < a->size2; ac++)
1006 for (size_t bc = 0; bc < b->size2; bc++, x++)
1008 double av = gsl_matrix_get (a, ar, ac);
1009 double bv = gsl_matrix_get (b, br, bc);
1010 gsl_matrix_set (k, y, x, av * bv);
1017 matrix_eval_LG10 (gsl_matrix *m)
1019 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1025 matrix_eval_LN (gsl_matrix *m)
1027 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1033 matrix_eval_MAGIC_odd (gsl_matrix *m, size_t n)
1035 /* Siamese method: https://en.wikipedia.org/wiki/Siamese_method. */
1038 for (size_t i = 1; i <= n * n; i++)
1040 gsl_matrix_set (m, y, x, i);
1042 size_t y1 = !y ? n - 1 : y - 1;
1043 size_t x1 = x + 1 >= n ? 0 : x + 1;
1044 if (gsl_matrix_get (m, y1, x1) == 0)
1050 y = y + 1 >= n ? 0 : y + 1;
1055 magic_exchange (gsl_matrix *m, size_t y1, size_t x1, size_t y2, size_t x2)
1057 double a = gsl_matrix_get (m, y1, x1);
1058 double b = gsl_matrix_get (m, y2, x2);
1059 gsl_matrix_set (m, y1, x1, b);
1060 gsl_matrix_set (m, y2, x2, a);
1064 matrix_eval_MAGIC_doubly_even (gsl_matrix *m, size_t n)
1068 /* A. Umar, "On the Construction of Even Order Magic Squares",
1069 https://arxiv.org/ftp/arxiv/papers/1202/1202.0948.pdf. */
1071 for (size_t i = 1; i <= n * n / 2; i++)
1073 gsl_matrix_set (m, y, x, i);
1083 for (size_t i = n * n; i > n * n / 2; i--)
1085 gsl_matrix_set (m, y, x, i);
1093 for (size_t y = 0; y < n; y++)
1094 for (size_t x = 0; x < n / 2; x++)
1096 unsigned int d = gsl_matrix_get (m, y, x);
1097 if (d % 2 != (y < n / 2))
1098 magic_exchange (m, y, x, y, n - x - 1);
1103 size_t x1 = n / 2 - 1;
1105 magic_exchange (m, y1, x1, y2, x1);
1106 magic_exchange (m, y1, x2, y2, x2);
1110 matrix_eval_MAGIC_singly_even (gsl_matrix *m, size_t n)
1112 /* A. Umar, "On the Construction of Even Order Magic Squares",
1113 https://arxiv.org/ftp/arxiv/papers/1202/1202.0948.pdf. */
1117 for (size_t i = 1; ; i++)
1119 gsl_matrix_set (m, y, x, i);
1120 if (++y == n / 2 - 1)
1132 for (size_t i = n * n; ; i--)
1134 gsl_matrix_set (m, y, x, i);
1135 if (++y == n / 2 - 1)
1144 for (size_t y = 0; y < n; y++)
1145 if (y != n / 2 - 1 && y != n / 2)
1146 for (size_t x = 0; x < n / 2; x++)
1148 unsigned int d = gsl_matrix_get (m, y, x);
1149 if (d % 2 != (y < n / 2))
1150 magic_exchange (m, y, x, y, n - x - 1);
1153 size_t a0 = (n * n - 2 * n) / 2 + 1;
1154 for (size_t i = 0; i < n / 2; i++)
1157 gsl_matrix_set (m, n / 2, i, a);
1158 gsl_matrix_set (m, n / 2 - 1, i, (n * n + 1) - a);
1160 for (size_t i = 0; i < n / 2; i++)
1162 size_t a = a0 + i + n / 2;
1163 gsl_matrix_set (m, n / 2 - 1, n - i - 1, a);
1164 gsl_matrix_set (m, n / 2, n - i - 1, (n * n + 1) - a);
1166 for (size_t x = 1; x < n / 2; x += 2)
1167 magic_exchange (m, n / 2, x, n / 2 - 1, x);
1168 for (size_t x = n / 2 + 2; x <= n - 3; x += 2)
1169 magic_exchange (m, n / 2, x, n / 2 - 1, x);
1170 size_t x1 = n / 2 - 2;
1171 size_t x2 = n / 2 + 1;
1172 size_t y1 = n / 2 - 2;
1173 size_t y2 = n / 2 + 1;
1174 magic_exchange (m, y1, x1, y2, x1);
1175 magic_exchange (m, y1, x2, y2, x2);
1179 matrix_eval_MAGIC (double n_)
1181 if (n_ < 3 || n_ >= sqrt (SIZE_MAX))
1183 msg (SE, _("MAGIC argument must be an integer 3 or greater."));
1188 gsl_matrix *m = gsl_matrix_calloc (n, n);
1190 matrix_eval_MAGIC_odd (m, n);
1192 matrix_eval_MAGIC_singly_even (m, n);
1194 matrix_eval_MAGIC_doubly_even (m, n);
1199 matrix_eval_MAKE (double r, double c, double value)
1201 if (r < 0 || r >= SIZE_MAX || c < 0 || c >= SIZE_MAX)
1203 msg (SE, _("Size arguments to MAKE must be integers."));
1207 gsl_matrix *m = gsl_matrix_alloc (r, c);
1208 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1214 matrix_eval_MDIAG (gsl_vector *v)
1216 gsl_matrix *m = gsl_matrix_calloc (v->size, v->size);
1217 gsl_vector diagonal = gsl_matrix_diagonal (m).vector;
1218 gsl_vector_memcpy (&diagonal, v);
1223 matrix_eval_MMAX (gsl_matrix *m)
1225 return gsl_matrix_max (m);
1229 matrix_eval_MMIN (gsl_matrix *m)
1231 return gsl_matrix_min (m);
1235 matrix_eval_MOD (gsl_matrix *m, double divisor)
1239 msg (SE, _("Divisor argument to MOD function must be nonzero."));
1243 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1244 *d = fmod (*d, divisor);
1249 matrix_eval_MSSQ (gsl_matrix *m)
1252 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1258 matrix_eval_MSUM (gsl_matrix *m)
1261 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1267 matrix_eval_NCOL (gsl_matrix *m)
1273 matrix_eval_NROW (gsl_matrix *m)
1279 matrix_eval_RANK (gsl_matrix *m)
1281 gsl_vector *tau = gsl_vector_alloc (MIN (m->size1, m->size2));
1282 gsl_linalg_QR_decomp (m, tau);
1283 gsl_vector_free (tau);
1285 return gsl_linalg_QRPT_rank (m, -1);
1289 matrix_eval_RESHAPE (gsl_matrix *m, double r_, double c_)
1291 if (r_ < 0 || r_ >= SIZE_MAX || c_ < 0 || c_ >= SIZE_MAX)
1293 msg (SE, _("Arguments 2 and 3 to RESHAPE must be integers."));
1298 if (size_overflow_p (xtimes (r, xmax (c, 1))) || c * r != m->size1 * m->size2)
1300 msg (SE, _("Product of RESHAPE arguments 2 and 3 differ from "
1301 "product of matrix dimensions."));
1305 gsl_matrix *dst = gsl_matrix_alloc (r, c);
1308 MATRIX_FOR_ALL_ELEMENTS (d, y2, x2, m)
1310 gsl_matrix_set (dst, y1, x1, *d);
1321 matrix_eval_row_extremum (gsl_matrix *m, bool min)
1326 return gsl_matrix_alloc (0, 1);
1328 gsl_matrix *rext = gsl_matrix_alloc (m->size1, 1);
1329 for (size_t y = 0; y < m->size1; y++)
1331 double ext = gsl_matrix_get (m, y, 0);
1332 for (size_t x = 1; x < m->size2; x++)
1334 double value = gsl_matrix_get (m, y, x);
1335 if (min ? value < ext : value > ext)
1338 gsl_matrix_set (rext, y, 0, ext);
1344 matrix_eval_RMAX (gsl_matrix *m)
1346 return matrix_eval_row_extremum (m, false);
1350 matrix_eval_RMIN (gsl_matrix *m)
1352 return matrix_eval_row_extremum (m, true);
1356 matrix_eval_RND (gsl_matrix *m)
1358 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1370 rank_compare_3way (const void *a_, const void *b_)
1372 const struct rank *a = a_;
1373 const struct rank *b = b_;
1375 return a->value < b->value ? -1 : a->value > b->value;
1379 matrix_eval_RNKORDER (gsl_matrix *m)
1381 size_t n = m->size1 * m->size2;
1382 struct rank *ranks = xmalloc (n * sizeof *ranks);
1384 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1385 ranks[i++] = (struct rank) { .y = y, .x = x, .value = *d };
1386 qsort (ranks, n, sizeof *ranks, rank_compare_3way);
1388 for (size_t i = 0; i < n; )
1391 for (j = i + 1; j < n; j++)
1392 if (ranks[i].value != ranks[j].value)
1395 double rank = (i + j + 1.0) / 2.0;
1396 for (size_t k = i; k < j; k++)
1397 gsl_matrix_set (m, ranks[k].y, ranks[k].x, rank);
1408 matrix_eval_row_sum (gsl_matrix *m, bool square)
1413 return gsl_matrix_alloc (0, 1);
1415 gsl_matrix *result = gsl_matrix_alloc (m->size1, 1);
1416 for (size_t y = 0; y < m->size1; y++)
1419 for (size_t x = 0; x < m->size2; x++)
1421 double d = gsl_matrix_get (m, y, x);
1422 sum += square ? pow2 (d) : d;
1424 gsl_matrix_set (result, y, 0, sum);
1430 matrix_eval_RSSQ (gsl_matrix *m)
1432 return matrix_eval_row_sum (m, true);
1436 matrix_eval_RSUM (gsl_matrix *m)
1438 return matrix_eval_row_sum (m, false);
1442 matrix_eval_SIN (gsl_matrix *m)
1444 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1450 matrix_eval_SOLVE (gsl_matrix *m1, gsl_matrix *m2)
1452 if (m1->size1 != m2->size1)
1454 msg (SE, _("SOLVE requires its arguments to have the same number of "
1455 "rows, but the first argument has dimensions %zu×%zu and "
1456 "the second %zu×%zu."),
1457 m1->size1, m1->size2,
1458 m2->size1, m2->size2);
1462 gsl_matrix *x = gsl_matrix_alloc (m2->size1, m2->size2);
1463 gsl_permutation *p = gsl_permutation_alloc (m1->size1);
1465 gsl_linalg_LU_decomp (m1, p, &signum);
1466 for (size_t i = 0; i < m2->size2; i++)
1468 gsl_vector bi = gsl_matrix_column (m2, i).vector;
1469 gsl_vector xi = gsl_matrix_column (x, i).vector;
1470 gsl_linalg_LU_solve (m1, p, &bi, &xi);
1472 gsl_permutation_free (p);
1477 matrix_eval_SQRT (gsl_matrix *m)
1479 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1483 msg (SE, _("Argument to SQRT must be nonnegative."));
1492 matrix_eval_SSCP (gsl_matrix *m)
1494 gsl_matrix *sscp = gsl_matrix_alloc (m->size2, m->size2);
1495 gsl_blas_dgemm (CblasTrans, CblasNoTrans, 1.0, m, m, 0.0, sscp);
1500 matrix_eval_SVAL (gsl_matrix *m)
1502 gsl_matrix *tmp_mat = NULL;
1503 if (m->size2 > m->size1)
1505 tmp_mat = gsl_matrix_alloc (m->size2, m->size1);
1506 gsl_matrix_transpose_memcpy (tmp_mat, m);
1511 gsl_matrix *V = gsl_matrix_alloc (m->size2, m->size2);
1512 gsl_vector *S = gsl_vector_alloc (m->size2);
1513 gsl_vector *work = gsl_vector_alloc (m->size2);
1514 gsl_linalg_SV_decomp (m, V, S, work);
1516 gsl_matrix *vals = gsl_matrix_alloc (m->size2, 1);
1517 for (size_t i = 0; i < m->size2; i++)
1518 gsl_matrix_set (vals, i, 0, gsl_vector_get (S, i));
1520 gsl_matrix_free (V);
1521 gsl_vector_free (S);
1522 gsl_vector_free (work);
1523 gsl_matrix_free (tmp_mat);
1529 matrix_eval_SWEEP (gsl_matrix *m, double d)
1531 if (d < 1 || d > SIZE_MAX)
1533 msg (SE, _("Scalar argument to SWEEP must be integer."));
1537 if (k >= MIN (m->size1, m->size2))
1539 msg (SE, _("Scalar argument to SWEEP must be integer less than or "
1540 "equal to the smaller of the matrix argument's rows and "
1545 double m_kk = gsl_matrix_get (m, k, k);
1546 if (fabs (m_kk) > 1e-19)
1548 gsl_matrix *a = gsl_matrix_alloc (m->size1, m->size2);
1549 MATRIX_FOR_ALL_ELEMENTS (a_ij, i, j, a)
1551 double m_ij = gsl_matrix_get (m, i, j);
1552 double m_ik = gsl_matrix_get (m, i, k);
1553 double m_kj = gsl_matrix_get (m, k, j);
1554 *a_ij = (i != k && j != k ? m_ij * m_kk - m_ik * m_kj
1563 for (size_t i = 0; i < m->size1; i++)
1565 gsl_matrix_set (m, i, k, 0);
1566 gsl_matrix_set (m, k, i, 0);
1573 matrix_eval_TRACE (gsl_matrix *m)
1576 size_t n = MIN (m->size1, m->size2);
1577 for (size_t i = 0; i < n; i++)
1578 sum += gsl_matrix_get (m, i, i);
1583 matrix_eval_T (gsl_matrix *m)
1585 return matrix_eval_TRANSPOS (m);
1589 matrix_eval_TRANSPOS (gsl_matrix *m)
1591 if (m->size1 == m->size2)
1593 gsl_matrix_transpose (m);
1598 gsl_matrix *t = gsl_matrix_alloc (m->size2, m->size1);
1599 gsl_matrix_transpose_memcpy (t, m);
1605 matrix_eval_TRUNC (gsl_matrix *m)
1607 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1613 matrix_eval_UNIFORM (double r_, double c_)
1615 if (r_ < 0 || r_ >= SIZE_MAX || c_ < 0 || c_ >= SIZE_MAX)
1617 msg (SE, _("Arguments to UNIFORM must be integers."));
1622 if (size_overflow_p (xtimes (r, xmax (c, 1))))
1624 msg (SE, _("Product of arguments to UNIFORM exceeds memory size."));
1628 gsl_matrix *m = gsl_matrix_alloc (r, c);
1629 MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
1630 *d = gsl_ran_flat (get_rng (), 0, 1);
1634 struct matrix_function
1638 size_t min_args, max_args;
1641 static struct matrix_expr *matrix_parse_expr (struct matrix_state *);
1643 static const struct matrix_function *
1644 matrix_parse_function_name (const char *token)
1646 static const struct matrix_function functions[] =
1648 #define F(NAME, PROTO) { #NAME, MOP_F_##NAME, PROTO##_MIN_ARGS, PROTO##_MAX_ARGS },
1652 enum { N_FUNCTIONS = sizeof functions / sizeof *functions };
1654 for (size_t i = 0; i < N_FUNCTIONS; i++)
1656 if (lex_id_match_n (ss_cstr (functions[i].name), ss_cstr (token), 3))
1657 return &functions[i];
1662 static struct read_file *
1663 read_file_create (struct matrix_state *s, struct file_handle *fh)
1665 for (size_t i = 0; i < s->n_read_files; i++)
1667 struct read_file *rf = s->read_files[i];
1675 struct read_file *rf = xmalloc (sizeof *rf);
1676 *rf = (struct read_file) { .file = fh };
1678 s->read_files = xrealloc (s->read_files,
1679 (s->n_read_files + 1) * sizeof *s->read_files);
1680 s->read_files[s->n_read_files++] = rf;
1684 static struct dfm_reader *
1685 read_file_open (struct read_file *rf)
1688 rf->reader = dfm_open_reader (rf->file, NULL, rf->encoding);
1693 read_file_destroy (struct read_file *rf)
1697 fh_unref (rf->file);
1698 dfm_close_reader (rf->reader);
1699 free (rf->encoding);
1704 static struct write_file *
1705 write_file_create (struct matrix_state *s, struct file_handle *fh)
1707 for (size_t i = 0; i < s->n_write_files; i++)
1709 struct write_file *wf = s->write_files[i];
1717 struct write_file *wf = xmalloc (sizeof *wf);
1718 *wf = (struct write_file) { .file = fh };
1720 s->write_files = xrealloc (s->write_files,
1721 (s->n_write_files + 1) * sizeof *s->write_files);
1722 s->write_files[s->n_write_files++] = wf;
1726 static struct dfm_writer *
1727 write_file_open (struct write_file *wf)
1730 wf->writer = dfm_open_writer (wf->file, wf->encoding);
1735 write_file_destroy (struct write_file *wf)
1739 fh_unref (wf->file);
1740 dfm_close_writer (wf->writer);
1741 free (wf->encoding);
1747 matrix_parse_function (struct matrix_state *s, const char *token,
1748 struct matrix_expr **exprp)
1751 if (lex_next_token (s->lexer, 1) != T_LPAREN)
1754 if (lex_match_id (s->lexer, "EOF"))
1757 struct file_handle *fh = fh_parse (s->lexer, FH_REF_FILE, s->session);
1761 if (!lex_force_match (s->lexer, T_RPAREN))
1767 struct read_file *rf = read_file_create (s, fh);
1769 struct matrix_expr *e = xmalloc (sizeof *e);
1770 *e = (struct matrix_expr) { .op = MOP_EOF, .eof = rf };
1775 const struct matrix_function *f = matrix_parse_function_name (token);
1779 lex_get_n (s->lexer, 2);
1781 struct matrix_expr *e = xmalloc (sizeof *e);
1782 *e = (struct matrix_expr) { .op = f->op, .subs = NULL };
1784 size_t allocated_subs = 0;
1787 struct matrix_expr *sub = matrix_parse_expr (s);
1791 if (e->n_subs >= allocated_subs)
1792 e->subs = x2nrealloc (e->subs, &allocated_subs, sizeof *e->subs);
1793 e->subs[e->n_subs++] = sub;
1795 while (lex_match (s->lexer, T_COMMA));
1796 if (!lex_force_match (s->lexer, T_RPAREN))
1803 matrix_expr_destroy (e);
1807 static struct matrix_expr *
1808 matrix_parse_primary (struct matrix_state *s)
1810 if (lex_is_number (s->lexer))
1812 double number = lex_number (s->lexer);
1814 return matrix_expr_create_number (number);
1816 else if (lex_is_string (s->lexer))
1818 char string[sizeof (double)];
1819 buf_copy_str_rpad (string, sizeof string, lex_tokcstr (s->lexer), ' ');
1823 memcpy (&number, string, sizeof number);
1824 return matrix_expr_create_number (number);
1826 else if (lex_match (s->lexer, T_LPAREN))
1828 struct matrix_expr *e = matrix_parse_or_xor (s);
1829 if (!e || !lex_force_match (s->lexer, T_RPAREN))
1831 matrix_expr_destroy (e);
1836 else if (lex_match (s->lexer, T_LCURLY))
1838 struct matrix_expr *e = matrix_parse_curly_semi (s);
1839 if (!e || !lex_force_match (s->lexer, T_RCURLY))
1841 matrix_expr_destroy (e);
1846 else if (lex_token (s->lexer) == T_ID)
1848 struct matrix_expr *retval;
1849 if (matrix_parse_function (s, lex_tokcstr (s->lexer), &retval))
1852 struct matrix_var *var = matrix_var_lookup (s, lex_tokss (s->lexer));
1855 lex_error (s->lexer, _("Unknown variable %s."),
1856 lex_tokcstr (s->lexer));
1861 struct matrix_expr *e = xmalloc (sizeof *e);
1862 *e = (struct matrix_expr) { .op = MOP_VARIABLE, .variable = var };
1865 else if (lex_token (s->lexer) == T_ALL)
1867 struct matrix_expr *retval;
1868 if (matrix_parse_function (s, "ALL", &retval))
1872 lex_error (s->lexer, NULL);
1876 static struct matrix_expr *matrix_parse_postfix (struct matrix_state *);
1879 matrix_parse_index_expr (struct matrix_state *s, struct matrix_expr **indexp)
1881 if (lex_match (s->lexer, T_COLON))
1888 *indexp = matrix_parse_expr (s);
1889 return *indexp != NULL;
1893 static struct matrix_expr *
1894 matrix_parse_postfix (struct matrix_state *s)
1896 struct matrix_expr *lhs = matrix_parse_primary (s);
1897 if (!lhs || !lex_match (s->lexer, T_LPAREN))
1900 struct matrix_expr *i0;
1901 if (!matrix_parse_index_expr (s, &i0))
1903 matrix_expr_destroy (lhs);
1906 if (lex_match (s->lexer, T_RPAREN))
1908 ? matrix_expr_create_2 (MOP_VEC_INDEX, lhs, i0)
1909 : matrix_expr_create_1 (MOP_VEC_ALL, lhs));
1910 else if (lex_match (s->lexer, T_COMMA))
1912 struct matrix_expr *i1;
1913 if (!matrix_parse_index_expr (s, &i1)
1914 || !lex_force_match (s->lexer, T_RPAREN))
1916 matrix_expr_destroy (lhs);
1917 matrix_expr_destroy (i0);
1918 matrix_expr_destroy (i1);
1921 return (i0 && i1 ? matrix_expr_create_3 (MOP_MAT_INDEX, lhs, i0, i1)
1922 : i0 ? matrix_expr_create_2 (MOP_ROW_INDEX, lhs, i0)
1923 : i1 ? matrix_expr_create_2 (MOP_COL_INDEX, lhs, i1)
1928 lex_error_expecting (s->lexer, "`)'", "`,'");
1933 static struct matrix_expr *
1934 matrix_parse_unary (struct matrix_state *s)
1936 if (lex_match (s->lexer, T_DASH))
1938 struct matrix_expr *lhs = matrix_parse_unary (s);
1939 return lhs ? matrix_expr_create_1 (MOP_NEGATE, lhs) : NULL;
1941 else if (lex_match (s->lexer, T_PLUS))
1942 return matrix_parse_unary (s);
1944 return matrix_parse_postfix (s);
1947 static struct matrix_expr *
1948 matrix_parse_seq (struct matrix_state *s)
1950 struct matrix_expr *start = matrix_parse_unary (s);
1951 if (!start || !lex_match (s->lexer, T_COLON))
1954 struct matrix_expr *end = matrix_parse_unary (s);
1957 matrix_expr_destroy (start);
1961 if (lex_match (s->lexer, T_COLON))
1963 struct matrix_expr *increment = matrix_parse_unary (s);
1966 matrix_expr_destroy (start);
1967 matrix_expr_destroy (end);
1970 return matrix_expr_create_3 (MOP_SEQ_BY, start, end, increment);
1973 return matrix_expr_create_2 (MOP_SEQ, start, end);
1976 static struct matrix_expr *
1977 matrix_parse_exp (struct matrix_state *s)
1979 struct matrix_expr *lhs = matrix_parse_seq (s);
1986 if (lex_match (s->lexer, T_EXP))
1988 else if (lex_match_phrase (s->lexer, "&**"))
1993 struct matrix_expr *rhs = matrix_parse_seq (s);
1996 matrix_expr_destroy (lhs);
1999 lhs = matrix_expr_create_2 (op, lhs, rhs);
2003 static struct matrix_expr *
2004 matrix_parse_mul_div (struct matrix_state *s)
2006 struct matrix_expr *lhs = matrix_parse_exp (s);
2013 if (lex_match (s->lexer, T_ASTERISK))
2015 else if (lex_match (s->lexer, T_SLASH))
2017 else if (lex_match_phrase (s->lexer, "&*"))
2019 else if (lex_match_phrase (s->lexer, "&/"))
2024 struct matrix_expr *rhs = matrix_parse_exp (s);
2027 matrix_expr_destroy (lhs);
2030 lhs = matrix_expr_create_2 (op, lhs, rhs);
2034 static struct matrix_expr *
2035 matrix_parse_add_sub (struct matrix_state *s)
2037 struct matrix_expr *lhs = matrix_parse_mul_div (s);
2044 if (lex_match (s->lexer, T_PLUS))
2046 else if (lex_match (s->lexer, T_DASH))
2048 else if (lex_token (s->lexer) == T_NEG_NUM)
2053 struct matrix_expr *rhs = matrix_parse_mul_div (s);
2056 matrix_expr_destroy (lhs);
2059 lhs = matrix_expr_create_2 (op, lhs, rhs);
2063 static struct matrix_expr *
2064 matrix_parse_relational (struct matrix_state *s)
2066 struct matrix_expr *lhs = matrix_parse_add_sub (s);
2073 if (lex_match (s->lexer, T_GT))
2075 else if (lex_match (s->lexer, T_GE))
2077 else if (lex_match (s->lexer, T_LT))
2079 else if (lex_match (s->lexer, T_LE))
2081 else if (lex_match (s->lexer, T_EQUALS) || lex_match (s->lexer, T_EQ))
2083 else if (lex_match (s->lexer, T_NE))
2088 struct matrix_expr *rhs = matrix_parse_add_sub (s);
2091 matrix_expr_destroy (lhs);
2094 lhs = matrix_expr_create_2 (op, lhs, rhs);
2098 static struct matrix_expr *
2099 matrix_parse_not (struct matrix_state *s)
2101 if (lex_match (s->lexer, T_NOT))
2103 struct matrix_expr *lhs = matrix_parse_not (s);
2104 return lhs ? matrix_expr_create_1 (MOP_NOT, lhs) : NULL;
2107 return matrix_parse_relational (s);
2110 static struct matrix_expr *
2111 matrix_parse_and (struct matrix_state *s)
2113 struct matrix_expr *lhs = matrix_parse_not (s);
2117 while (lex_match (s->lexer, T_AND))
2119 struct matrix_expr *rhs = matrix_parse_not (s);
2122 matrix_expr_destroy (lhs);
2125 lhs = matrix_expr_create_2 (MOP_AND, lhs, rhs);
2130 static struct matrix_expr *
2131 matrix_parse_or_xor (struct matrix_state *s)
2133 struct matrix_expr *lhs = matrix_parse_and (s);
2140 if (lex_match (s->lexer, T_OR))
2142 else if (lex_match_id (s->lexer, "XOR"))
2147 struct matrix_expr *rhs = matrix_parse_and (s);
2150 matrix_expr_destroy (lhs);
2153 lhs = matrix_expr_create_2 (op, lhs, rhs);
2157 static struct matrix_expr *
2158 matrix_parse_expr (struct matrix_state *s)
2160 return matrix_parse_or_xor (s);
2163 /* Expression evaluation. */
2166 matrix_op_eval (enum matrix_op op, double a, double b)
2170 case MOP_ADD_ELEMS: return a + b;
2171 case MOP_SUB_ELEMS: return a - b;
2172 case MOP_MUL_ELEMS: return a * b;
2173 case MOP_DIV_ELEMS: return a / b;
2174 case MOP_EXP_ELEMS: return pow (a, b);
2175 case MOP_GT: return a > b;
2176 case MOP_GE: return a >= b;
2177 case MOP_LT: return a < b;
2178 case MOP_LE: return a <= b;
2179 case MOP_EQ: return a == b;
2180 case MOP_NE: return a != b;
2181 case MOP_AND: return (a > 0) && (b > 0);
2182 case MOP_OR: return (a > 0) || (b > 0);
2183 case MOP_XOR: return (a > 0) != (b > 0);
2185 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
2194 case MOP_PASTE_HORZ:
2195 case MOP_PASTE_VERT:
2211 matrix_op_name (enum matrix_op op)
2215 case MOP_ADD_ELEMS: return "+";
2216 case MOP_SUB_ELEMS: return "-";
2217 case MOP_MUL_ELEMS: return "&*";
2218 case MOP_DIV_ELEMS: return "&/";
2219 case MOP_EXP_ELEMS: return "&**";
2220 case MOP_GT: return ">";
2221 case MOP_GE: return ">=";
2222 case MOP_LT: return "<";
2223 case MOP_LE: return "<=";
2224 case MOP_EQ: return "=";
2225 case MOP_NE: return "<>";
2226 case MOP_AND: return "AND";
2227 case MOP_OR: return "OR";
2228 case MOP_XOR: return "XOR";
2230 #define F(NAME, PROTOTYPE) case MOP_F_##NAME:
2239 case MOP_PASTE_HORZ:
2240 case MOP_PASTE_VERT:
2256 is_scalar (const gsl_matrix *m)
2258 return m->size1 == 1 && m->size2 == 1;
2262 to_scalar (const gsl_matrix *m)
2264 assert (is_scalar (m));
2265 return gsl_matrix_get (m, 0, 0);
2269 matrix_expr_evaluate_elementwise (enum matrix_op op,
2270 gsl_matrix *a, gsl_matrix *b)
2274 double be = to_scalar (b);
2275 for (size_t r = 0; r < a->size1; r++)
2276 for (size_t c = 0; c < a->size2; c++)
2278 double *ae = gsl_matrix_ptr (a, r, c);
2279 *ae = matrix_op_eval (op, *ae, be);
2283 else if (is_scalar (a))
2285 double ae = to_scalar (a);
2286 for (size_t r = 0; r < b->size1; r++)
2287 for (size_t c = 0; c < b->size2; c++)
2289 double *be = gsl_matrix_ptr (b, r, c);
2290 *be = matrix_op_eval (op, ae, *be);
2294 else if (a->size1 == b->size1 && a->size2 == b->size2)
2296 for (size_t r = 0; r < a->size1; r++)
2297 for (size_t c = 0; c < a->size2; c++)
2299 double *ae = gsl_matrix_ptr (a, r, c);
2300 double be = gsl_matrix_get (b, r, c);
2301 *ae = matrix_op_eval (op, *ae, be);
2307 msg (SE, _("Operands to %s must have the same dimensions or one "
2308 "must be a scalar, not %zu×%zu and %zu×%zu matrices."),
2309 matrix_op_name (op), a->size1, a->size2, b->size1, b->size2);
2315 matrix_expr_evaluate_mul_mat (gsl_matrix *a, gsl_matrix *b)
2317 if (is_scalar (a) || is_scalar (b))
2318 return matrix_expr_evaluate_elementwise (MOP_MUL_ELEMS, a, b);
2320 if (a->size2 != b->size1)
2322 msg (SE, _("Matrices with dimensions %zu×%zu and %zu×%zu are "
2323 "not conformable for multiplication."),
2324 a->size1, a->size2, b->size1, b->size2);
2328 gsl_matrix *c = gsl_matrix_alloc (a->size1, b->size2);
2329 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, a, b, 0.0, c);
2334 swap_matrix (gsl_matrix **a, gsl_matrix **b)
2336 gsl_matrix *tmp = *a;
2342 mul_matrix (gsl_matrix **z, const gsl_matrix *x, const gsl_matrix *y,
2345 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, x, y, 0.0, *tmp);
2346 swap_matrix (z, tmp);
2350 square_matrix (gsl_matrix **x, gsl_matrix **tmp)
2352 mul_matrix (x, *x, *x, tmp);
2356 matrix_expr_evaluate_exp_mat (gsl_matrix *x_, gsl_matrix *b)
2359 if (x->size1 != x->size2)
2361 msg (SE, _("Matrix exponentation with ** requires a square matrix on "
2362 "the left-hand size, not one with dimensions %zu×%zu."),
2363 x->size1, x->size2);
2368 msg (SE, _("Matrix exponentiation with ** requires a scalar on the "
2369 "right-hand side, not a matrix with dimensions %zu×%zu."),
2370 b->size1, b->size2);
2373 double bf = to_scalar (b);
2374 if (bf != floor (bf) || bf <= LONG_MIN || bf > LONG_MAX)
2376 msg (SE, _("Exponent %.1f in matrix multiplication is non-integer "
2377 "or outside the valid range."), bf);
2382 gsl_matrix *y_ = gsl_matrix_alloc (x->size1, x->size2);
2384 gsl_matrix_set_identity (y);
2388 gsl_matrix *t_ = gsl_matrix_alloc (x->size1, x->size2);
2390 for (unsigned long int n = labs (bl); n > 1; n /= 2)
2393 mul_matrix (&y, x, y, &t);
2394 square_matrix (&x, &t);
2397 square_matrix (&x, &t);
2399 mul_matrix (&y, x, y, &t);
2403 /* Garbage collection.
2405 There are three matrices: 'x_', 'y_', and 't_', and 'x', 'y', and 't' are
2406 a permutation of them. We are returning one of them; that one must not be
2407 destroyed. We must not destroy 'x_' because the caller owns it. */
2409 gsl_matrix_free (y_);
2411 gsl_matrix_free (t_);
2417 matrix_expr_evaluate_seq (gsl_matrix *start_, gsl_matrix *end_,
2420 if (!is_scalar (start_) || !is_scalar (end_) || (by_ && !is_scalar (by_)))
2422 msg (SE, _("All operands of : operator must be scalars."));
2426 long int start = to_scalar (start_);
2427 long int end = to_scalar (end_);
2428 long int by = by_ ? to_scalar (by_) : 1;
2432 msg (SE, _("The increment operand to : must be nonzero."));
2436 long int n = (end >= start && by > 0 ? (end - start + by) / by
2437 : end < start && by < 0 ? (start - end - by) / -by
2439 gsl_matrix *m = gsl_matrix_alloc (1, n);
2440 for (long int i = 0; i < n; i++)
2441 gsl_matrix_set (m, 0, i, start + i * by);
2446 matrix_expr_evaluate_not (gsl_matrix *a)
2448 for (size_t r = 0; r < a->size1; r++)
2449 for (size_t c = 0; c < a->size2; c++)
2451 double *ae = gsl_matrix_ptr (a, r, c);
2458 matrix_expr_evaluate_paste_horz (gsl_matrix *a, gsl_matrix *b)
2460 if (a->size1 != b->size1)
2462 if (!a->size1 || !a->size2)
2464 else if (!b->size1 || !b->size2)
2467 msg (SE, _("All columns in a matrix must have the same number of rows, "
2468 "but this tries to paste matrices with %zu and %zu rows."),
2469 a->size1, b->size1);
2473 gsl_matrix *c = gsl_matrix_alloc (a->size1, a->size2 + b->size2);
2474 for (size_t y = 0; y < a->size1; y++)
2476 for (size_t x = 0; x < a->size2; x++)
2477 gsl_matrix_set (c, y, x, gsl_matrix_get (a, y, x));
2478 for (size_t x = 0; x < b->size2; x++)
2479 gsl_matrix_set (c, y, x + a->size2, gsl_matrix_get (b, y, x));
2485 matrix_expr_evaluate_paste_vert (gsl_matrix *a, gsl_matrix *b)
2487 if (a->size2 != b->size2)
2489 if (!a->size1 || !a->size2)
2491 else if (!b->size1 || !b->size2)
2494 msg (SE, _("All rows in a matrix must have the same number of columns, "
2495 "but this tries to stack matrices with %zu and %zu columns."),
2496 a->size2, b->size2);
2500 gsl_matrix *c = gsl_matrix_alloc (a->size1 + b->size1, a->size2);
2501 for (size_t x = 0; x < a->size2; x++)
2503 for (size_t y = 0; y < a->size1; y++)
2504 gsl_matrix_set (c, y, x, gsl_matrix_get (a, y, x));
2505 for (size_t y = 0; y < b->size1; y++)
2506 gsl_matrix_set (c, y + a->size1, x, gsl_matrix_get (b, y, x));
2512 matrix_to_vector (gsl_matrix *m)
2515 gsl_vector v = to_vector (m);
2516 assert (v.block == m->block || !v.block);
2520 return xmemdup (&v, sizeof v);
2534 #define INDEX_VECTOR_INIT (struct index_vector) { .n = 0 }
2537 matrix_normalize_index_vector (const gsl_matrix *m, size_t size,
2538 enum index_type index_type, size_t other_size,
2539 struct index_vector *iv)
2548 msg (SE, _("Vector index must be scalar or vector, not a "
2550 m->size1, m->size2);
2554 msg (SE, _("Matrix row index must be scalar or vector, not a "
2556 m->size1, m->size2);
2560 msg (SE, _("Matrix column index must be scalar or vector, not a "
2562 m->size1, m->size2);
2568 gsl_vector v = to_vector (CONST_CAST (gsl_matrix *, m));
2569 *iv = (struct index_vector) {
2570 .indexes = xnmalloc (v.size, sizeof *iv->indexes),
2573 for (size_t i = 0; i < v.size; i++)
2575 double index = gsl_vector_get (&v, i);
2576 if (index < 1 || index >= size + 1)
2581 msg (SE, _("Index %g is out of range for vector "
2582 "with %zu elements."), index, size);
2586 msg (SE, _("%g is not a valid row index for "
2587 "a %zu×%zu matrix."),
2588 index, size, other_size);
2592 msg (SE, _("%g is not a valid column index for "
2593 "a %zu×%zu matrix."),
2594 index, other_size, size);
2601 iv->indexes[i] = index - 1;
2607 *iv = (struct index_vector) {
2608 .indexes = xnmalloc (size, sizeof *iv->indexes),
2611 for (size_t i = 0; i < size; i++)
2618 matrix_expr_evaluate_vec_all (gsl_matrix *sm)
2620 if (!is_vector (sm))
2622 msg (SE, _("Vector index operator may not be applied to "
2623 "a %zu×%zu matrix."),
2624 sm->size1, sm->size2);
2632 matrix_expr_evaluate_vec_index (gsl_matrix *sm, gsl_matrix *im)
2634 if (!matrix_expr_evaluate_vec_all (sm))
2637 gsl_vector sv = to_vector (sm);
2638 struct index_vector iv;
2639 if (!matrix_normalize_index_vector (im, sv.size, IV_VECTOR, 0, &iv))
2642 gsl_matrix *dm = gsl_matrix_alloc (sm->size1 == 1 ? 1 : iv.n,
2643 sm->size1 == 1 ? iv.n : 1);
2644 gsl_vector dv = to_vector (dm);
2645 for (size_t dx = 0; dx < iv.n; dx++)
2647 size_t sx = iv.indexes[dx];
2648 gsl_vector_set (&dv, dx, gsl_vector_get (&sv, sx));
2656 matrix_expr_evaluate_mat_index (gsl_matrix *sm, gsl_matrix *im0,
2659 struct index_vector iv0;
2660 if (!matrix_normalize_index_vector (im0, sm->size1, IV_ROW, sm->size2, &iv0))
2663 struct index_vector iv1;
2664 if (!matrix_normalize_index_vector (im1, sm->size2, IV_COLUMN, sm->size1,
2671 gsl_matrix *dm = gsl_matrix_alloc (iv0.n, iv1.n);
2672 for (size_t dy = 0; dy < iv0.n; dy++)
2674 size_t sy = iv0.indexes[dy];
2676 for (size_t dx = 0; dx < iv1.n; dx++)
2678 size_t sx = iv1.indexes[dx];
2679 gsl_matrix_set (dm, dy, dx, gsl_matrix_get (sm, sy, sx));
2687 #define F(NAME, PROTOTYPE) \
2688 static gsl_matrix *matrix_expr_evaluate_##PROTOTYPE ( \
2689 const char *name, gsl_matrix *[], size_t, \
2690 matrix_proto_##PROTOTYPE *);
2695 check_scalar_arg (const char *name, gsl_matrix *subs[], size_t index)
2697 if (!is_scalar (subs[index]))
2699 msg (SE, _("Function %s argument %zu must be a scalar, "
2700 "not a %zu×%zu matrix."),
2701 name, index + 1, subs[index]->size1, subs[index]->size2);
2708 check_vector_arg (const char *name, gsl_matrix *subs[], size_t index)
2710 if (!is_vector (subs[index]))
2712 msg (SE, _("Function %s argument %zu must be a vector, "
2713 "not a %zu×%zu matrix."),
2714 name, index + 1, subs[index]->size1, subs[index]->size2);
2721 to_scalar_args (const char *name, gsl_matrix *subs[], size_t n_subs, double d[])
2723 for (size_t i = 0; i < n_subs; i++)
2725 if (!check_scalar_arg (name, subs, i))
2727 d[i] = to_scalar (subs[i]);
2733 matrix_expr_evaluate_m_d (const char *name,
2734 gsl_matrix *subs[], size_t n_subs,
2735 matrix_proto_m_d *f)
2737 assert (n_subs == 1);
2740 return to_scalar_args (name, subs, n_subs, &d) ? f(d) : NULL;
2744 matrix_expr_evaluate_m_dd (const char *name,
2745 gsl_matrix *subs[], size_t n_subs,
2746 matrix_proto_m_dd *f)
2748 assert (n_subs == 2);
2751 return to_scalar_args (name, subs, n_subs, d) ? f(d[0], d[1]) : NULL;
2755 matrix_expr_evaluate_m_ddd (const char *name,
2756 gsl_matrix *subs[], size_t n_subs,
2757 matrix_proto_m_ddd *f)
2759 assert (n_subs == 3);
2762 return to_scalar_args (name, subs, n_subs, d) ? f(d[0], d[1], d[2]) : NULL;
2766 matrix_expr_evaluate_m_m (const char *name UNUSED,
2767 gsl_matrix *subs[], size_t n_subs,
2768 matrix_proto_m_m *f)
2770 assert (n_subs == 1);
2775 matrix_expr_evaluate_m_md (const char *name UNUSED,
2776 gsl_matrix *subs[], size_t n_subs,
2777 matrix_proto_m_md *f)
2779 assert (n_subs == 2);
2780 if (!check_scalar_arg (name, subs, 1))
2782 return f (subs[0], to_scalar (subs[1]));
2786 matrix_expr_evaluate_m_mdd (const char *name UNUSED,
2787 gsl_matrix *subs[], size_t n_subs,
2788 matrix_proto_m_mdd *f)
2790 assert (n_subs == 3);
2791 if (!check_scalar_arg (name, subs, 1) || !check_scalar_arg (name, subs, 2))
2793 return f (subs[0], to_scalar (subs[1]), to_scalar (subs[2]));
2797 matrix_expr_evaluate_m_mm (const char *name UNUSED,
2798 gsl_matrix *subs[], size_t n_subs,
2799 matrix_proto_m_mm *f)
2801 assert (n_subs == 2);
2802 return f (subs[0], subs[1]);
2806 matrix_expr_evaluate_m_v (const char *name,
2807 gsl_matrix *subs[], size_t n_subs,
2808 matrix_proto_m_v *f)
2810 assert (n_subs == 1);
2811 if (!check_vector_arg (name, subs, 0))
2813 gsl_vector v = to_vector (subs[0]);
2818 matrix_expr_evaluate_d_m (const char *name UNUSED,
2819 gsl_matrix *subs[], size_t n_subs,
2820 matrix_proto_d_m *f)
2822 assert (n_subs == 1);
2824 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2825 gsl_matrix_set (m, 0, 0, f (subs[0]));
2830 matrix_expr_evaluate_m_any (const char *name UNUSED,
2831 gsl_matrix *subs[], size_t n_subs,
2832 matrix_proto_m_any *f)
2834 return f (subs, n_subs);
2838 matrix_expr_evaluate_IDENT (const char *name,
2839 gsl_matrix *subs[], size_t n_subs,
2840 matrix_proto_IDENT *f)
2842 assert (n_subs <= 2);
2845 if (!to_scalar_args (name, subs, n_subs, d))
2848 return f (d[0], d[n_subs - 1]);
2852 matrix_expr_evaluate (const struct matrix_expr *e)
2854 if (e->op == MOP_NUMBER)
2856 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2857 gsl_matrix_set (m, 0, 0, e->number);
2860 else if (e->op == MOP_VARIABLE)
2862 const gsl_matrix *src = e->variable->value;
2865 msg (SE, _("Uninitialized variable %s used in expression."),
2870 gsl_matrix *dst = gsl_matrix_alloc (src->size1, src->size2);
2871 gsl_matrix_memcpy (dst, src);
2874 else if (e->op == MOP_EOF)
2876 struct dfm_reader *reader = read_file_open (e->eof);
2877 gsl_matrix *m = gsl_matrix_alloc (1, 1);
2878 gsl_matrix_set (m, 0, 0, !reader || dfm_eof (reader));
2882 enum { N_LOCAL = 3 };
2883 gsl_matrix *local_subs[N_LOCAL];
2884 gsl_matrix **subs = (e->n_subs < N_LOCAL
2886 : xmalloc (e->n_subs * sizeof *subs));
2888 for (size_t i = 0; i < e->n_subs; i++)
2890 subs[i] = matrix_expr_evaluate (e->subs[i]);
2893 for (size_t j = 0; j < i; j++)
2894 gsl_matrix_free (subs[j]);
2895 if (subs != local_subs)
2901 gsl_matrix *result = NULL;
2904 #define F(NAME, PROTOTYPE) \
2905 case MOP_F_##NAME: \
2906 result = matrix_expr_evaluate_##PROTOTYPE (#NAME, \
2908 matrix_eval_##NAME); \
2914 gsl_matrix_scale (subs[0], -1.0);
2932 result = matrix_expr_evaluate_elementwise (e->op, subs[0], subs[1]);
2936 result = matrix_expr_evaluate_not (subs[0]);
2940 result = matrix_expr_evaluate_seq (subs[0], subs[1], NULL);
2944 result = matrix_expr_evaluate_seq (subs[0], subs[1], subs[2]);
2948 result = matrix_expr_evaluate_mul_mat (subs[0], subs[1]);
2952 result = matrix_expr_evaluate_exp_mat (subs[0], subs[1]);
2955 case MOP_PASTE_HORZ:
2956 result = matrix_expr_evaluate_paste_horz (subs[0], subs[1]);
2959 case MOP_PASTE_VERT:
2960 result = matrix_expr_evaluate_paste_vert (subs[0], subs[1]);
2964 result = gsl_matrix_alloc (0, 0);
2968 result = matrix_expr_evaluate_vec_index (subs[0], subs[1]);
2972 result = matrix_expr_evaluate_vec_all (subs[0]);
2976 result = matrix_expr_evaluate_mat_index (subs[0], subs[1], subs[2]);
2980 result = matrix_expr_evaluate_mat_index (subs[0], subs[1], NULL);
2984 result = matrix_expr_evaluate_mat_index (subs[0], NULL, subs[1]);
2993 for (size_t i = 0; i < e->n_subs; i++)
2994 if (subs[i] != result)
2995 gsl_matrix_free (subs[i]);
2996 if (subs != local_subs)
3002 matrix_expr_evaluate_scalar (const struct matrix_expr *e, const char *context,
3005 gsl_matrix *m = matrix_expr_evaluate (e);
3011 msg (SE, _("Expression for %s must evaluate to scalar, "
3012 "not a %zu×%zu matrix."),
3013 context, m->size1, m->size2);
3014 gsl_matrix_free (m);
3019 gsl_matrix_free (m);
3024 matrix_expr_evaluate_integer (const struct matrix_expr *e, const char *context,
3028 if (!matrix_expr_evaluate_scalar (e, context, &d))
3032 if (d < LONG_MIN || d > LONG_MAX)
3034 msg (SE, _("Expression for %s is outside the integer range."), context);
3041 struct matrix_lvalue
3043 struct matrix_var *var;
3044 struct matrix_expr *indexes[2];
3049 matrix_lvalue_destroy (struct matrix_lvalue *lvalue)
3053 for (size_t i = 0; i < lvalue->n_indexes; i++)
3054 matrix_expr_destroy (lvalue->indexes[i]);
3059 static struct matrix_lvalue *
3060 matrix_lvalue_parse (struct matrix_state *s)
3062 struct matrix_lvalue *lvalue = xzalloc (sizeof *lvalue);
3063 if (!lex_force_id (s->lexer))
3065 lvalue->var = matrix_var_lookup (s, lex_tokss (s->lexer));
3066 if (lex_next_token (s->lexer, 1) == T_LPAREN)
3070 msg (SE, _("Undefined variable %s."), lex_tokcstr (s->lexer));
3075 lex_get_n (s->lexer, 2);
3077 if (!matrix_parse_index_expr (s, &lvalue->indexes[0]))
3079 lvalue->n_indexes++;
3081 if (lex_match (s->lexer, T_COMMA))
3083 if (!matrix_parse_index_expr (s, &lvalue->indexes[1]))
3085 lvalue->n_indexes++;
3087 if (!lex_force_match (s->lexer, T_RPAREN))
3093 lvalue->var = matrix_var_create (s, lex_tokss (s->lexer));
3099 matrix_lvalue_destroy (lvalue);
3104 matrix_lvalue_evaluate_vector (struct matrix_expr *e, size_t size,
3105 enum index_type index_type, size_t other_size,
3106 struct index_vector *iv)
3111 m = matrix_expr_evaluate (e);
3118 bool ok = matrix_normalize_index_vector (m, size, index_type,
3120 gsl_matrix_free (m);
3125 matrix_lvalue_assign_vector (struct matrix_lvalue *lvalue,
3126 struct index_vector *iv, gsl_matrix *sm)
3128 gsl_vector dv = to_vector (lvalue->var->value);
3130 /* Convert source matrix 'sm' to source vector 'sv'. */
3131 if (!is_vector (sm))
3133 msg (SE, _("Can't assign %zu×%zu matrix to subvector."),
3134 sm->size1, sm->size2);
3137 gsl_vector sv = to_vector (sm);
3138 if (iv->n != sv.size)
3140 msg (SE, _("Can't assign %zu-element vector "
3141 "to %zu-element subvector."), sv.size, iv->n);
3145 /* Assign elements. */
3146 for (size_t x = 0; x < iv->n; x++)
3147 gsl_vector_set (&dv, iv->indexes[x], gsl_vector_get (&sv, x));
3152 matrix_lvalue_assign_matrix (struct matrix_lvalue *lvalue,
3153 struct index_vector *iv0,
3154 struct index_vector *iv1, gsl_matrix *sm)
3156 gsl_matrix *dm = lvalue->var->value;
3158 /* Convert source matrix 'sm' to source vector 'sv'. */
3159 if (iv0->n != sm->size1)
3161 msg (SE, _("Row index vector for assignment to %s has %zu elements "
3162 "but source matrix has %zu rows."),
3163 lvalue->var->name, iv0->n, sm->size1);
3166 if (iv1->n != sm->size2)
3168 msg (SE, _("Column index vector for assignment to %s has %zu elements "
3169 "but source matrix has %zu columns."),
3170 lvalue->var->name, iv1->n, sm->size2);
3174 /* Assign elements. */
3175 for (size_t y = 0; y < iv0->n; y++)
3177 size_t f0 = iv0->indexes[y];
3178 for (size_t x = 0; x < iv1->n; x++)
3180 size_t f1 = iv1->indexes[x];
3181 gsl_matrix_set (dm, f0, f1, gsl_matrix_get (sm, y, x));
3187 /* Takes ownership of M. */
3189 matrix_lvalue_assign (struct matrix_lvalue *lvalue,
3190 struct index_vector *iv0, struct index_vector *iv1,
3193 if (!lvalue->n_indexes)
3195 gsl_matrix_free (lvalue->var->value);
3196 lvalue->var->value = sm;
3201 bool ok = (lvalue->n_indexes == 1
3202 ? matrix_lvalue_assign_vector (lvalue, iv0, sm)
3203 : matrix_lvalue_assign_matrix (lvalue, iv0, iv1, sm));
3204 free (iv0->indexes);
3205 free (iv1->indexes);
3206 gsl_matrix_free (sm);
3212 matrix_lvalue_evaluate (struct matrix_lvalue *lvalue,
3213 struct index_vector *iv0,
3214 struct index_vector *iv1)
3216 *iv0 = INDEX_VECTOR_INIT;
3217 *iv1 = INDEX_VECTOR_INIT;
3218 if (!lvalue->n_indexes)
3221 /* Validate destination matrix exists and has the right shape. */
3222 gsl_matrix *dm = lvalue->var->value;
3225 msg (SE, _("Undefined variable %s."), lvalue->var->name);
3228 else if (dm->size1 == 0 || dm->size2 == 0)
3230 msg (SE, _("Cannot index %zu×%zu matrix."),
3231 dm->size1, dm->size2);
3234 else if (lvalue->n_indexes == 1)
3236 if (!is_vector (dm))
3238 msg (SE, _("Can't use vector indexing on %zu×%zu matrix %s."),
3239 dm->size1, dm->size2, lvalue->var->name);
3242 return matrix_lvalue_evaluate_vector (lvalue->indexes[0],
3243 MAX (dm->size1, dm->size2),
3248 assert (lvalue->n_indexes == 2);
3249 if (!matrix_lvalue_evaluate_vector (lvalue->indexes[0], dm->size1,
3250 IV_ROW, dm->size2, iv0))
3253 if (!matrix_lvalue_evaluate_vector (lvalue->indexes[1], dm->size2,
3254 IV_COLUMN, dm->size1, iv1))
3256 free (iv0->indexes);
3263 /* Takes ownership of M. */
3265 matrix_lvalue_evaluate_and_assign (struct matrix_lvalue *lvalue, gsl_matrix *sm)
3267 struct index_vector iv0, iv1;
3268 if (!matrix_lvalue_evaluate (lvalue, &iv0, &iv1))
3270 gsl_matrix_free (sm);
3274 return matrix_lvalue_assign (lvalue, &iv0, &iv1, sm);
3278 /* Matrix command. */
3282 struct matrix_cmd **commands;
3286 static void matrix_cmds_uninit (struct matrix_cmds *);
3290 enum matrix_cmd_type
3313 struct compute_command
3315 struct matrix_lvalue *lvalue;
3316 struct matrix_expr *rvalue;
3320 struct print_command
3322 struct matrix_expr *expression;
3323 bool use_default_format;
3324 struct fmt_spec format;
3326 int space; /* -1 means NEWPAGE. */
3330 struct string_array literals; /* CLABELS/RLABELS. */
3331 struct matrix_expr *expr; /* CNAMES/RNAMES. */
3337 struct do_if_command
3341 struct matrix_expr *condition;
3342 struct matrix_cmds commands;
3352 struct matrix_var *var;
3353 struct matrix_expr *start;
3354 struct matrix_expr *end;
3355 struct matrix_expr *increment;
3357 /* Loop conditions. */
3358 struct matrix_expr *top_condition;
3359 struct matrix_expr *bottom_condition;
3362 struct matrix_cmds commands;
3366 struct display_command
3368 struct matrix_state *state;
3374 struct release_command
3376 struct matrix_var **vars;
3383 struct matrix_expr *expression;
3384 struct file_handle *outfile;
3385 struct string_array *variables;
3386 struct matrix_expr *names;
3387 struct stringi_set strings;
3393 struct read_file *rf;
3394 struct matrix_lvalue *dst;
3395 struct matrix_expr *size;
3397 enum fmt_type format;
3405 struct write_command
3407 struct write_file *wf;
3408 struct matrix_expr *expression;
3410 enum fmt_type format;
3414 bool hold; /* XXX */
3420 struct matrix_lvalue *dst;
3421 struct file_handle *file;
3423 struct string_array variables;
3424 struct matrix_var *names;
3426 /* Treatment of missing values. */
3431 MGET_ERROR, /* Flag error on command. */
3432 MGET_ACCEPT, /* Accept without change, user-missing only. */
3433 MGET_OMIT, /* Drop this case. */
3434 MGET_RECODE /* Recode to 'substitute'. */
3437 double substitute; /* MGET_RECODE only. */
3443 struct msave_command
3445 struct msave_common *common;
3447 struct matrix_expr *expr;
3448 const char *rowtype;
3449 struct matrix_expr *factors;
3450 struct matrix_expr *splits;
3456 struct matrix_state *state;
3457 struct file_handle *file;
3458 struct stringi_set rowtypes;
3462 struct eigen_command
3464 struct matrix_expr *expr;
3465 struct matrix_var *evec;
3466 struct matrix_var *eval;
3470 struct setdiag_command
3472 struct matrix_var *dst;
3473 struct matrix_expr *expr;
3479 struct matrix_expr *expr;
3480 struct matrix_var *u;
3481 struct matrix_var *s;
3482 struct matrix_var *v;
3488 static struct matrix_cmd *matrix_parse_command (struct matrix_state *);
3489 static bool matrix_cmd_execute (struct matrix_cmd *);
3490 static void matrix_cmd_destroy (struct matrix_cmd *);
3493 static struct matrix_cmd *
3494 matrix_parse_compute (struct matrix_state *s)
3496 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
3497 *cmd = (struct matrix_cmd) {
3498 .type = MCMD_COMPUTE,
3499 .compute = { .lvalue = NULL },
3502 struct compute_command *compute = &cmd->compute;
3503 compute->lvalue = matrix_lvalue_parse (s);
3504 if (!compute->lvalue)
3507 if (!lex_force_match (s->lexer, T_EQUALS))
3510 compute->rvalue = matrix_parse_expr (s);
3511 if (!compute->rvalue)
3517 matrix_cmd_destroy (cmd);
3522 matrix_cmd_execute_compute (struct compute_command *compute)
3524 gsl_matrix *value = matrix_expr_evaluate (compute->rvalue);
3528 matrix_lvalue_evaluate_and_assign (compute->lvalue, value);
3532 print_labels_destroy (struct print_labels *labels)
3536 string_array_destroy (&labels->literals);
3537 matrix_expr_destroy (labels->expr);
3543 parse_literal_print_labels (struct matrix_state *s,
3544 struct print_labels **labelsp)
3546 lex_match (s->lexer, T_EQUALS);
3547 print_labels_destroy (*labelsp);
3548 *labelsp = xzalloc (sizeof **labelsp);
3549 while (lex_token (s->lexer) != T_SLASH
3550 && lex_token (s->lexer) != T_ENDCMD
3551 && lex_token (s->lexer) != T_STOP)
3553 struct string label = DS_EMPTY_INITIALIZER;
3554 while (lex_token (s->lexer) != T_COMMA
3555 && lex_token (s->lexer) != T_SLASH
3556 && lex_token (s->lexer) != T_ENDCMD
3557 && lex_token (s->lexer) != T_STOP)
3559 if (!ds_is_empty (&label))
3560 ds_put_byte (&label, ' ');
3562 if (lex_token (s->lexer) == T_STRING)
3563 ds_put_cstr (&label, lex_tokcstr (s->lexer));
3566 char *rep = lex_next_representation (s->lexer, 0, 0);
3567 ds_put_cstr (&label, rep);
3572 string_array_append_nocopy (&(*labelsp)->literals,
3573 ds_steal_cstr (&label));
3575 if (!lex_match (s->lexer, T_COMMA))
3581 parse_expr_print_labels (struct matrix_state *s, struct print_labels **labelsp)
3583 lex_match (s->lexer, T_EQUALS);
3584 struct matrix_expr *e = matrix_parse_exp (s);
3588 print_labels_destroy (*labelsp);
3589 *labelsp = xzalloc (sizeof **labelsp);
3590 (*labelsp)->expr = e;
3594 static struct matrix_cmd *
3595 matrix_parse_print (struct matrix_state *s)
3597 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
3598 *cmd = (struct matrix_cmd) {
3601 .use_default_format = true,
3605 if (lex_token (s->lexer) != T_SLASH && lex_token (s->lexer) != T_ENDCMD)
3608 for (size_t i = 0; ; i++)
3610 enum token_type t = lex_next_token (s->lexer, i);
3611 if (t == T_LPAREN || t == T_LBRACK || t == T_LCURLY)
3613 else if ((t == T_RPAREN || t == T_RBRACK || t == T_RCURLY) && depth)
3615 else if ((t == T_SLASH && !depth) || t == T_ENDCMD || t == T_STOP)
3618 cmd->print.title = lex_next_representation (s->lexer, 0, i - 1);
3623 cmd->print.expression = matrix_parse_exp (s);
3624 if (!cmd->print.expression)
3628 while (lex_match (s->lexer, T_SLASH))
3630 if (lex_match_id (s->lexer, "FORMAT"))
3632 lex_match (s->lexer, T_EQUALS);
3633 if (!parse_format_specifier (s->lexer, &cmd->print.format))
3635 cmd->print.use_default_format = false;
3637 else if (lex_match_id (s->lexer, "TITLE"))
3639 lex_match (s->lexer, T_EQUALS);
3640 if (!lex_force_string (s->lexer))
3642 free (cmd->print.title);
3643 cmd->print.title = ss_xstrdup (lex_tokss (s->lexer));
3646 else if (lex_match_id (s->lexer, "SPACE"))
3648 lex_match (s->lexer, T_EQUALS);
3649 if (lex_match_id (s->lexer, "NEWPAGE"))
3650 cmd->print.space = -1;
3651 else if (lex_force_int_range (s->lexer, "SPACE", 1, INT_MAX))
3653 cmd->print.space = lex_integer (s->lexer);
3659 else if (lex_match_id (s->lexer, "RLABELS"))
3660 parse_literal_print_labels (s, &cmd->print.rlabels);
3661 else if (lex_match_id (s->lexer, "CLABELS"))
3662 parse_literal_print_labels (s, &cmd->print.clabels);
3663 else if (lex_match_id (s->lexer, "RNAMES"))
3665 if (!parse_expr_print_labels (s, &cmd->print.rlabels))
3668 else if (lex_match_id (s->lexer, "CNAMES"))
3670 if (!parse_expr_print_labels (s, &cmd->print.clabels))
3675 lex_error_expecting (s->lexer, "FORMAT", "TITLE", "SPACE",
3676 "RLABELS", "CLABELS", "RNAMES", "CNAMES");
3684 matrix_cmd_destroy (cmd);
3689 matrix_is_integer (const gsl_matrix *m)
3691 for (size_t y = 0; y < m->size1; y++)
3692 for (size_t x = 0; x < m->size2; x++)
3694 double d = gsl_matrix_get (m, y, x);
3702 matrix_max_magnitude (const gsl_matrix *m)
3705 for (size_t y = 0; y < m->size1; y++)
3706 for (size_t x = 0; x < m->size2; x++)
3708 double d = fabs (gsl_matrix_get (m, y, x));
3716 format_fits (struct fmt_spec format, double x)
3718 char *s = data_out (&(union value) { .f = x }, NULL,
3719 &format, settings_get_fmt_settings ());
3720 bool fits = *s != '*' && !strchr (s, 'E');
3725 static struct fmt_spec
3726 default_format (const gsl_matrix *m, int *log_scale)
3730 double max = matrix_max_magnitude (m);
3732 if (matrix_is_integer (m))
3733 for (int w = 1; w <= 12; w++)
3735 struct fmt_spec format = { .type = FMT_F, .w = w };
3736 if (format_fits (format, -max))
3740 if (max >= 1e9 || max <= 1e-4)
3743 snprintf (s, sizeof s, "%.1e", max);
3745 const char *e = strchr (s, 'e');
3747 *log_scale = atoi (e + 1);
3750 return (struct fmt_spec) { .type = FMT_F, .w = 13, .d = 10 };
3754 trimmed_string (double d)
3756 struct substring s = ss_buffer ((char *) &d, sizeof d);
3757 ss_rtrim (&s, ss_cstr (" "));
3758 return ss_xstrdup (s);
3761 static struct string_array *
3762 print_labels_get (const struct print_labels *labels, size_t n,
3763 const char *prefix, bool truncate)
3768 struct string_array *out = xzalloc (sizeof *out);
3769 if (labels->literals.n)
3770 string_array_clone (out, &labels->literals);
3771 else if (labels->expr)
3773 gsl_matrix *m = matrix_expr_evaluate (labels->expr);
3774 if (m && is_vector (m))
3776 gsl_vector v = to_vector (m);
3777 for (size_t i = 0; i < v.size; i++)
3778 string_array_append_nocopy (out, trimmed_string (
3779 gsl_vector_get (&v, i)));
3781 gsl_matrix_free (m);
3787 string_array_append_nocopy (out, xasprintf ("%s%zu", prefix,
3790 string_array_append (out, "");
3793 string_array_delete (out, out->n - 1);
3796 for (size_t i = 0; i < out->n; i++)
3798 char *s = out->strings[i];
3799 s[strnlen (s, 8)] = '\0';
3806 matrix_cmd_print_space (int space)
3809 output_item_submit (page_break_item_create ());
3810 for (int i = 0; i < space; i++)
3811 output_log ("%s", "");
3815 matrix_cmd_print_text (const struct print_command *print, const gsl_matrix *m,
3816 struct fmt_spec format, int log_scale)
3818 matrix_cmd_print_space (print->space);
3820 output_log ("%s", print->title);
3822 output_log (" 10 ** %d X", log_scale);
3824 struct string_array *clabels = print_labels_get (print->clabels,
3825 m->size2, "col", true);
3826 if (clabels && format.w < 8)
3828 struct string_array *rlabels = print_labels_get (print->rlabels,
3829 m->size1, "row", true);
3833 struct string line = DS_EMPTY_INITIALIZER;
3835 ds_put_byte_multiple (&line, ' ', 8);
3836 for (size_t x = 0; x < m->size2; x++)
3837 ds_put_format (&line, " %*s", format.w, clabels->strings[x]);
3838 output_log_nocopy (ds_steal_cstr (&line));
3841 double scale = pow (10.0, log_scale);
3842 bool numeric = fmt_is_numeric (format.type);
3843 for (size_t y = 0; y < m->size1; y++)
3845 struct string line = DS_EMPTY_INITIALIZER;
3847 ds_put_format (&line, "%-8s", rlabels->strings[y]);
3849 for (size_t x = 0; x < m->size2; x++)
3851 double f = gsl_matrix_get (m, y, x);
3853 ? data_out (&(union value) { .f = f / scale}, NULL,
3854 &format, settings_get_fmt_settings ())
3855 : trimmed_string (f));
3856 ds_put_format (&line, " %s", s);
3859 output_log_nocopy (ds_steal_cstr (&line));
3862 string_array_destroy (rlabels);
3864 string_array_destroy (clabels);
3869 create_print_dimension (struct pivot_table *table, enum pivot_axis_type axis,
3870 const struct print_labels *print_labels, size_t n,
3871 const char *name, const char *prefix)
3873 struct string_array *labels = print_labels_get (print_labels, n, prefix,
3875 struct pivot_dimension *d = pivot_dimension_create (table, axis, name);
3876 for (size_t i = 0; i < n; i++)
3877 pivot_category_create_leaf (
3879 ? pivot_value_new_user_text (labels->strings[i], SIZE_MAX)
3880 : pivot_value_new_integer (i + 1)));
3882 d->hide_all_labels = true;
3883 string_array_destroy (labels);
3888 matrix_cmd_print_tables (const struct print_command *print, const gsl_matrix *m,
3889 struct fmt_spec format, int log_scale)
3891 struct pivot_table *table = pivot_table_create__ (
3892 pivot_value_new_user_text (print->title ? print->title : "", SIZE_MAX),
3895 create_print_dimension (table, PIVOT_AXIS_ROW, print->rlabels, m->size1,
3897 create_print_dimension (table, PIVOT_AXIS_COLUMN, print->clabels, m->size2,
3898 N_("Columns"), "col");
3900 struct pivot_footnote *footnote = NULL;
3903 char *s = xasprintf ("× 10**%d", log_scale);
3904 footnote = pivot_table_create_footnote (
3905 table, pivot_value_new_user_text_nocopy (s));
3908 double scale = pow (10.0, log_scale);
3909 bool numeric = fmt_is_numeric (format.type);
3910 for (size_t y = 0; y < m->size1; y++)
3911 for (size_t x = 0; x < m->size2; x++)
3913 double f = gsl_matrix_get (m, y, x);
3914 struct pivot_value *v;
3917 v = pivot_value_new_number (f / scale);
3918 v->numeric.format = format;
3921 v = pivot_value_new_user_text_nocopy (trimmed_string (f));
3923 pivot_value_add_footnote (v, footnote);
3924 pivot_table_put2 (table, y, x, v);
3927 pivot_table_submit (table);
3931 matrix_cmd_execute_print (const struct print_command *print)
3933 if (print->expression)
3935 gsl_matrix *m = matrix_expr_evaluate (print->expression);
3940 struct fmt_spec format = (print->use_default_format
3941 ? default_format (m, &log_scale)
3944 if (settings_get_mdisplay () == SETTINGS_MDISPLAY_TEXT)
3945 matrix_cmd_print_text (print, m, format, log_scale);
3947 matrix_cmd_print_tables (print, m, format, log_scale);
3949 gsl_matrix_free (m);
3953 matrix_cmd_print_space (print->space);
3955 output_log ("%s", print->title);
3962 matrix_parse_commands (struct matrix_state *s, struct matrix_cmds *c,
3963 const char *command_name,
3964 const char *stop1, const char *stop2)
3966 lex_end_of_command (s->lexer);
3967 lex_discard_rest_of_command (s->lexer);
3969 size_t allocated = 0;
3972 while (lex_token (s->lexer) == T_ENDCMD)
3975 if (lex_at_phrase (s->lexer, stop1)
3976 || (stop2 && lex_at_phrase (s->lexer, stop2)))
3979 if (lex_at_phrase (s->lexer, "END MATRIX"))
3981 msg (SE, _("Premature END MATRIX within %s."), command_name);
3985 struct matrix_cmd *cmd = matrix_parse_command (s);
3989 if (c->n >= allocated)
3990 c->commands = x2nrealloc (c->commands, &allocated, sizeof *c->commands);
3991 c->commands[c->n++] = cmd;
3996 matrix_parse_do_if_clause (struct matrix_state *s,
3997 struct do_if_command *ifc,
3998 bool parse_condition,
3999 size_t *allocated_clauses)
4001 if (ifc->n_clauses >= *allocated_clauses)
4002 ifc->clauses = x2nrealloc (ifc->clauses, allocated_clauses,
4003 sizeof *ifc->clauses);
4004 struct do_if_clause *c = &ifc->clauses[ifc->n_clauses++];
4005 *c = (struct do_if_clause) { .condition = NULL };
4007 if (parse_condition)
4009 c->condition = matrix_parse_expr (s);
4014 return matrix_parse_commands (s, &c->commands, "DO IF", "ELSE", "END IF");
4017 static struct matrix_cmd *
4018 matrix_parse_do_if (struct matrix_state *s)
4020 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4021 *cmd = (struct matrix_cmd) {
4023 .do_if = { .n_clauses = 0 }
4026 size_t allocated_clauses = 0;
4029 if (!matrix_parse_do_if_clause (s, &cmd->do_if, true, &allocated_clauses))
4032 while (lex_match_phrase (s->lexer, "ELSE IF"));
4034 if (lex_match_id (s->lexer, "ELSE")
4035 && !matrix_parse_do_if_clause (s, &cmd->do_if, false, &allocated_clauses))
4038 if (!lex_match_phrase (s->lexer, "END IF"))
4043 matrix_cmd_destroy (cmd);
4048 matrix_cmd_execute_do_if (struct do_if_command *cmd)
4050 for (size_t i = 0; i < cmd->n_clauses; i++)
4052 struct do_if_clause *c = &cmd->clauses[i];
4056 if (!matrix_expr_evaluate_scalar (c->condition,
4057 i ? "ELSE IF" : "DO IF",
4062 for (size_t j = 0; j < c->commands.n; j++)
4063 if (!matrix_cmd_execute (c->commands.commands[j]))
4070 static struct matrix_cmd *
4071 matrix_parse_loop (struct matrix_state *s)
4073 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4074 *cmd = (struct matrix_cmd) { .type = MCMD_LOOP, .loop = { .var = NULL } };
4076 struct loop_command *loop = &cmd->loop;
4077 if (lex_token (s->lexer) == T_ID && lex_next_token (s->lexer, 1) == T_EQUALS)
4079 struct substring name = lex_tokss (s->lexer);
4080 loop->var = matrix_var_lookup (s, name);
4082 loop->var = matrix_var_create (s, name);
4087 loop->start = matrix_parse_expr (s);
4088 if (!loop->start || !lex_force_match (s->lexer, T_TO))
4091 loop->end = matrix_parse_expr (s);
4095 if (lex_match (s->lexer, T_BY))
4097 loop->increment = matrix_parse_expr (s);
4098 if (!loop->increment)
4103 if (lex_match_id (s->lexer, "IF"))
4105 loop->top_condition = matrix_parse_expr (s);
4106 if (!loop->top_condition)
4110 bool was_in_loop = s->in_loop;
4112 bool ok = matrix_parse_commands (s, &loop->commands, "LOOP",
4114 s->in_loop = was_in_loop;
4118 if (!lex_match_phrase (s->lexer, "END LOOP"))
4121 if (lex_match_id (s->lexer, "IF"))
4123 loop->bottom_condition = matrix_parse_expr (s);
4124 if (!loop->bottom_condition)
4131 matrix_cmd_destroy (cmd);
4136 matrix_cmd_execute_loop (struct loop_command *cmd)
4140 long int increment = 1;
4143 if (!matrix_expr_evaluate_integer (cmd->start, "LOOP", &value)
4144 || !matrix_expr_evaluate_integer (cmd->end, "TO", &end)
4146 && !matrix_expr_evaluate_integer (cmd->increment, "BY",
4150 if (increment > 0 ? value > end
4151 : increment < 0 ? value < end
4156 int mxloops = settings_get_mxloops ();
4157 for (int i = 0; i < mxloops; i++)
4162 && (cmd->var->value->size1 != 1 || cmd->var->value->size2 != 1))
4164 gsl_matrix_free (cmd->var->value);
4165 cmd->var->value = NULL;
4167 if (!cmd->var->value)
4168 cmd->var->value = gsl_matrix_alloc (1, 1);
4170 gsl_matrix_set (cmd->var->value, 0, 0, value);
4173 if (cmd->top_condition)
4176 if (!matrix_expr_evaluate_scalar (cmd->top_condition, "LOOP IF",
4181 for (size_t j = 0; j < cmd->commands.n; j++)
4182 if (!matrix_cmd_execute (cmd->commands.commands[j]))
4185 if (cmd->bottom_condition)
4188 if (!matrix_expr_evaluate_scalar (cmd->bottom_condition,
4189 "END LOOP IF", &d) || d > 0)
4196 if (increment > 0 ? value > end : value < end)
4202 static struct matrix_cmd *
4203 matrix_parse_break (struct matrix_state *s)
4207 msg (SE, _("BREAK not inside LOOP."));
4211 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4212 *cmd = (struct matrix_cmd) { .type = MCMD_BREAK };
4216 static struct matrix_cmd *
4217 matrix_parse_display (struct matrix_state *s)
4219 bool dictionary = false;
4220 bool status = false;
4221 while (lex_token (s->lexer) == T_ID)
4223 if (lex_match_id (s->lexer, "DICTIONARY"))
4225 else if (lex_match_id (s->lexer, "STATUS"))
4229 lex_error_expecting (s->lexer, "DICTIONARY", "STATUS");
4233 if (!dictionary && !status)
4234 dictionary = status = true;
4236 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4237 *cmd = (struct matrix_cmd) {
4238 .type = MCMD_DISPLAY,
4241 .dictionary = dictionary,
4249 compare_matrix_var_pointers (const void *a_, const void *b_)
4251 const struct matrix_var *const *ap = a_;
4252 const struct matrix_var *const *bp = b_;
4253 const struct matrix_var *a = *ap;
4254 const struct matrix_var *b = *bp;
4255 return strcmp (a->name, b->name);
4259 matrix_cmd_execute_display (struct display_command *cmd)
4261 const struct matrix_state *s = cmd->state;
4263 struct pivot_table *table = pivot_table_create (N_("Matrix Variables"));
4264 pivot_dimension_create (
4265 table, PIVOT_AXIS_COLUMN, N_("Property"),
4266 N_("Rows"), N_("Columns"), N_("Size (kB)"));
4268 const struct matrix_var **vars = xmalloc (hmap_count (&s->vars) * sizeof *vars);
4271 const struct matrix_var *var;
4272 HMAP_FOR_EACH (var, struct matrix_var, hmap_node, &s->vars)
4274 vars[n_vars++] = var;
4275 qsort (vars, n_vars, sizeof *vars, compare_matrix_var_pointers);
4277 struct pivot_dimension *rows = pivot_dimension_create (
4278 table, PIVOT_AXIS_ROW, N_("Variable"));
4279 for (size_t i = 0; i < n_vars; i++)
4281 const struct matrix_var *var = vars[i];
4282 pivot_category_create_leaf (
4283 rows->root, pivot_value_new_user_text (var->name, SIZE_MAX));
4285 size_t r = var->value->size1;
4286 size_t c = var->value->size2;
4287 double values[] = { r, c, r * c * sizeof (double) / 1024 };
4288 for (size_t j = 0; j < sizeof values / sizeof *values; j++)
4289 pivot_table_put2 (table, j, i, pivot_value_new_integer (values[j]));
4291 pivot_table_submit (table);
4294 static struct matrix_cmd *
4295 matrix_parse_release (struct matrix_state *s)
4297 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4298 *cmd = (struct matrix_cmd) { .type = MCMD_RELEASE };
4300 size_t allocated_vars = 0;
4301 while (lex_token (s->lexer) == T_ID)
4303 struct matrix_var *var = matrix_var_lookup (s, lex_tokss (s->lexer));
4306 if (cmd->release.n_vars >= allocated_vars)
4307 cmd->release.vars = x2nrealloc (cmd->release.vars, &allocated_vars,
4308 sizeof *cmd->release.vars);
4309 cmd->release.vars[cmd->release.n_vars++] = var;
4312 lex_error (s->lexer, _("Variable name expected."));
4315 if (!lex_match (s->lexer, T_COMMA))
4323 matrix_cmd_execute_release (struct release_command *cmd)
4325 for (size_t i = 0; i < cmd->n_vars; i++)
4327 struct matrix_var *var = cmd->vars[i];
4328 gsl_matrix_free (var->value);
4333 static struct matrix_cmd *
4334 matrix_parse_save (struct matrix_state *s)
4336 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4337 *cmd = (struct matrix_cmd) {
4340 .strings = STRINGI_SET_INITIALIZER (cmd->save.strings)
4344 struct save_command *save = &cmd->save;
4345 save->expression = matrix_parse_exp (s);
4346 if (!save->expression)
4349 while (lex_match (s->lexer, T_SLASH))
4351 if (lex_match_id (s->lexer, "OUTFILE"))
4353 lex_match (s->lexer, T_EQUALS);
4355 fh_unref (save->outfile);
4356 save->outfile = (lex_match (s->lexer, T_ASTERISK)
4358 : fh_parse (s->lexer, FH_REF_FILE, s->session));
4362 else if (lex_match_id (s->lexer, "VARIABLES"))
4364 lex_match (s->lexer, T_EQUALS);
4368 struct dictionary *d = dict_create (get_default_encoding ());
4369 bool ok = parse_DATA_LIST_vars (s->lexer, d, &names, &n,
4370 PV_NO_SCRATCH | PV_NO_DUPLICATE);
4375 string_array_destroy (save->variables);
4376 if (!save->variables)
4377 save->variables = xmalloc (sizeof *save->variables);
4378 *save->variables = (struct string_array) {
4384 else if (lex_match_id (s->lexer, "NAMES"))
4386 lex_match (s->lexer, T_EQUALS);
4387 matrix_expr_destroy (save->names);
4388 save->names = matrix_parse_exp (s);
4392 else if (lex_match_id (s->lexer, "STRINGS"))
4394 lex_match (s->lexer, T_EQUALS);
4395 while (lex_token (s->lexer) == T_ID)
4397 stringi_set_insert (&save->strings, lex_tokcstr (s->lexer));
4399 if (!lex_match (s->lexer, T_COMMA))
4405 lex_error_expecting (s->lexer, "OUTFILE", "VARIABLES", "NAMES",
4413 if (s->prev_save_outfile)
4414 save->outfile = fh_ref (s->prev_save_outfile);
4417 lex_sbc_missing ("OUTFILE");
4421 fh_unref (s->prev_save_outfile);
4422 s->prev_save_outfile = fh_ref (save->outfile);
4424 if (save->variables && save->names)
4426 msg (SW, _("VARIABLES and NAMES both specified; ignoring NAMES."));
4427 matrix_expr_destroy (save->names);
4434 matrix_cmd_destroy (cmd);
4439 matrix_cmd_execute_save (const struct save_command *save)
4441 assert (save->outfile != fh_inline_file ()); /* XXX not yet implemented */
4443 gsl_matrix *m = matrix_expr_evaluate (save->expression);
4448 struct dictionary *dict = dict_create (get_default_encoding ());
4449 struct string_array names = { .n = 0 };
4450 if (save->variables)
4451 string_array_clone (&names, save->variables);
4452 else if (save->names)
4454 gsl_matrix *nm = matrix_expr_evaluate (save->names);
4455 if (nm && is_vector (nm))
4457 gsl_vector nv = to_vector (nm);
4458 for (size_t i = 0; i < nv.size; i++)
4460 char *name = trimmed_string (gsl_vector_get (&nv, i));
4461 if (dict_id_is_valid (dict, name, true))
4462 string_array_append_nocopy (&names, name);
4469 struct stringi_set strings;
4470 stringi_set_clone (&strings, &save->strings);
4472 for (size_t i = 0; dict_get_var_cnt (dict) < m->size2; i++)
4477 name = names.strings[i];
4480 snprintf (tmp_name, sizeof tmp_name, "COL%zu", i + 1);
4484 int width = stringi_set_delete (&strings, name) ? 8 : 0;
4485 struct variable *var = dict_create_var (dict, name, width);
4488 msg (SE, _("Duplicate variable name %s in SAVE statement."),
4494 if (!stringi_set_is_empty (&strings))
4496 const char *example = stringi_set_node_get_string (
4497 stringi_set_first (&strings));
4498 msg (SE, ngettext ("STRINGS specified a variable %s, but no variable "
4499 "with that name was found on SAVE.",
4500 "STRINGS specified %2$zu variables, including %1$s, "
4501 "whose names were not found on SAVE.",
4502 stringi_set_count (&strings)),
4503 example, stringi_set_count (&strings));
4506 stringi_set_destroy (&strings);
4507 string_array_destroy (&names);
4511 gsl_matrix_free (m);
4516 struct casewriter *writer = any_writer_open (save->outfile, dict);
4519 gsl_matrix_free (m);
4524 const struct caseproto *proto = dict_get_proto (dict);
4525 for (size_t y = 0; y < m->size1; y++)
4527 struct ccase *c = case_create (proto);
4528 for (size_t x = 0; x < m->size2; x++)
4530 double d = gsl_matrix_get (m, y, x);
4531 int width = caseproto_get_width (proto, x);
4532 union value *value = case_data_rw_idx (c, x);
4536 memcpy (value->s, &d, width);
4538 casewriter_write (writer, c);
4540 casewriter_destroy (writer);
4542 gsl_matrix_free (m);
4546 static struct matrix_cmd *
4547 matrix_parse_read (struct matrix_state *s)
4549 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4550 *cmd = (struct matrix_cmd) {
4552 .read = { .format = FMT_F },
4555 struct file_handle *fh = NULL;
4556 char *encoding = NULL;
4557 struct read_command *read = &cmd->read;
4558 read->dst = matrix_lvalue_parse (s);
4563 int repetitions = 0;
4564 int record_width = 0;
4565 bool seen_format = false;
4566 while (lex_match (s->lexer, T_SLASH))
4568 if (lex_match_id (s->lexer, "FILE"))
4570 lex_match (s->lexer, T_EQUALS);
4573 fh = fh_parse (s->lexer, FH_REF_FILE, NULL);
4577 else if (lex_match_id (s->lexer, "ENCODING"))
4579 lex_match (s->lexer, T_EQUALS);
4580 if (!lex_force_string (s->lexer))
4584 encoding = ss_xstrdup (lex_tokss (s->lexer));
4588 else if (lex_match_id (s->lexer, "FIELD"))
4590 lex_match (s->lexer, T_EQUALS);
4592 if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX))
4594 read->c1 = lex_integer (s->lexer);
4596 if (!lex_force_match (s->lexer, T_TO)
4597 || !lex_force_int_range (s->lexer, "TO", read->c1, INT_MAX))
4599 read->c2 = lex_integer (s->lexer) + 1;
4602 record_width = read->c2 - read->c1;
4603 if (lex_match (s->lexer, T_BY))
4605 if (!lex_force_int_range (s->lexer, "BY", 1,
4606 read->c2 - read->c1))
4608 by = lex_integer (s->lexer);
4611 if (record_width % by)
4613 msg (SE, _("BY %d does not evenly divide record width %d."),
4621 else if (lex_match_id (s->lexer, "SIZE"))
4623 lex_match (s->lexer, T_EQUALS);
4624 read->size = matrix_parse_exp (s);
4628 else if (lex_match_id (s->lexer, "MODE"))
4630 lex_match (s->lexer, T_EQUALS);
4631 if (lex_match_id (s->lexer, "RECTANGULAR"))
4632 read->symmetric = false;
4633 else if (lex_match_id (s->lexer, "SYMMETRIC"))
4634 read->symmetric = true;
4637 lex_error_expecting (s->lexer, "RECTANGULAR", "SYMMETRIC");
4641 else if (lex_match_id (s->lexer, "REREAD"))
4642 read->reread = true;
4643 else if (lex_match_id (s->lexer, "FORMAT"))
4647 lex_sbc_only_once ("FORMAT");
4652 lex_match (s->lexer, T_EQUALS);
4654 if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer))
4657 const char *p = lex_tokcstr (s->lexer);
4658 if (c_isdigit (p[0]))
4660 repetitions = atoi (p);
4661 p += strspn (p, "0123456789");
4662 if (!fmt_from_name (p, &read->format))
4664 lex_error (s->lexer, _("Unknown format %s."), p);
4669 else if (!fmt_from_name (p, &read->format))
4671 struct fmt_spec format;
4672 if (!parse_format_specifier (s->lexer, &format))
4674 read->format = format.type;
4681 lex_error_expecting (s->lexer, "FILE", "FIELD", "MODE",
4682 "REREAD", "FORMAT");
4689 lex_sbc_missing ("FIELD");
4693 if (!read->dst->n_indexes && !read->size)
4695 msg (SE, _("SIZE is required for reading data into a full matrix "
4696 "(as opposed to a submatrix)."));
4702 if (s->prev_read_file)
4703 fh = fh_ref (s->prev_read_file);
4706 lex_sbc_missing ("FILE");
4710 fh_unref (s->prev_read_file);
4711 s->prev_read_file = fh_ref (fh);
4713 read->rf = read_file_create (s, fh);
4717 free (read->rf->encoding);
4718 read->rf->encoding = encoding;
4722 /* Field width may be specified in multiple ways:
4725 2. The format on FORMAT.
4726 3. The repetition factor on FORMAT.
4728 (2) and (3) are mutually exclusive.
4730 If more than one of these is present, they must agree. If none of them is
4731 present, then free-field format is used.
4733 if (repetitions > record_width)
4735 msg (SE, _("%d repetitions cannot fit in record width %d."),
4736 repetitions, record_width);
4739 int w = (repetitions ? record_width / repetitions
4745 msg (SE, _("FORMAT specifies %d repetitions with record width %d, "
4746 "which implies field width %d, "
4747 "but BY specifies field width %d."),
4748 repetitions, record_width, w, by);
4750 msg (SE, _("FORMAT specifies field width %d but BY specifies %d."),
4759 matrix_cmd_destroy (cmd);
4765 matrix_read_set_field (struct read_command *read, struct dfm_reader *reader,
4766 gsl_matrix *m, struct substring p, size_t y, size_t x)
4768 const char *input_encoding = dfm_reader_get_encoding (reader);
4770 char *error = data_in (p, input_encoding, read->format,
4771 settings_get_fmt_settings (), &v, 0, NULL);
4772 /* XXX report error if value is missing */
4774 msg (SW, _("GET parse error (%.*s): %s"), (int) p.length, p.string, error);
4777 gsl_matrix_set (m, y, x, v.f);
4778 if (read->symmetric && x != y)
4779 gsl_matrix_set (m, x, y, v.f);
4784 matrix_read_line (struct read_command *read, struct dfm_reader *reader,
4785 struct substring *line)
4787 if (dfm_eof (reader))
4789 msg (SE, _("Unexpected end of file reading matrix data."));
4792 dfm_expand_tabs (reader);
4793 *line = ss_substr (dfm_get_record (reader),
4794 read->c1 - 1, read->c2 - read->c1);
4799 matrix_read (struct read_command *read, struct dfm_reader *reader,
4802 for (size_t y = 0; y < m->size1; y++)
4804 size_t nx = read->symmetric ? y + 1 : m->size2;
4806 struct substring line = ss_empty ();
4807 for (size_t x = 0; x < nx; x++)
4814 ss_ltrim (&line, ss_cstr (" ,"));
4815 if (!ss_is_empty (line))
4817 if (!matrix_read_line (read, reader, &line))
4819 dfm_forward_record (reader);
4822 ss_get_bytes (&line, ss_cspan (line, ss_cstr (" ,")), &p);
4826 if (!matrix_read_line (read, reader, &line))
4828 size_t fields_per_line = (read->c2 - read->c1) / read->w;
4829 int f = x % fields_per_line;
4830 if (f == fields_per_line - 1)
4831 dfm_forward_record (reader);
4833 p = ss_substr (line, read->w * f, read->w);
4836 matrix_read_set_field (read, reader, m, p, y, x);
4840 dfm_forward_record (reader);
4843 ss_ltrim (&line, ss_cstr (" ,"));
4844 if (!ss_is_empty (line))
4845 msg (SW, _("Trailing garbage on line \"%.*s\""),
4846 (int) line.length, line.string);
4852 matrix_cmd_execute_read (struct read_command *read)
4854 struct index_vector iv0, iv1;
4855 if (!matrix_lvalue_evaluate (read->dst, &iv0, &iv1))
4858 size_t size[2] = { SIZE_MAX, SIZE_MAX };
4861 gsl_matrix *m = matrix_expr_evaluate (read->size);
4867 msg (SE, _("SIZE must evaluate to a scalar or a 2-element vector, "
4868 "not a %zu×%zu matrix."), m->size1, m->size2);
4869 gsl_matrix_free (m);
4875 gsl_vector v = to_vector (m);
4879 d[0] = gsl_vector_get (&v, 0);
4882 else if (v.size == 2)
4884 d[0] = gsl_vector_get (&v, 0);
4885 d[1] = gsl_vector_get (&v, 1);
4889 msg (SE, _("SIZE must evaluate to a scalar or a 2-element vector, "
4890 "not a %zu×%zu matrix."),
4891 m->size1, m->size2),
4892 gsl_matrix_free (m);
4897 gsl_matrix_free (m);
4899 if (d[0] < 0 || d[0] > SIZE_MAX || d[1] < 0 || d[1] > SIZE_MAX)
4901 msg (SE, _("SIZE (%g,%g) is outside valid range."), d[0], d[1]);
4911 if (read->dst->n_indexes)
4913 size_t submatrix_size[2];
4914 if (read->dst->n_indexes == 2)
4916 submatrix_size[0] = iv0.n;
4917 submatrix_size[1] = iv1.n;
4919 else if (read->dst->var->value->size1 == 1)
4921 submatrix_size[0] = 1;
4922 submatrix_size[1] = iv0.n;
4926 submatrix_size[0] = iv0.n;
4927 submatrix_size[1] = 1;
4932 if (size[0] != submatrix_size[0] || size[1] != submatrix_size[1])
4934 msg (SE, _("SIZE (%zu,%zu) differs from submatrix dimensions "
4937 submatrix_size[0], submatrix_size[1]);
4945 size[0] = submatrix_size[0];
4946 size[1] = submatrix_size[1];
4950 struct dfm_reader *reader = read_file_open (read->rf);
4952 dfm_reread_record (reader, 1);
4954 if (read->symmetric && size[0] != size[1])
4956 msg (SE, _("Cannot read non-square %zu×%zu matrix "
4957 "using READ with MODE=SYMMETRIC."),
4963 gsl_matrix *tmp = gsl_matrix_calloc (size[0], size[1]);
4964 matrix_read (read, reader, tmp);
4965 matrix_lvalue_assign (read->dst, &iv0, &iv1, tmp);
4968 static struct matrix_cmd *
4969 matrix_parse_write (struct matrix_state *s)
4971 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
4972 *cmd = (struct matrix_cmd) {
4974 .write = { .format = FMT_F },
4977 struct file_handle *fh = NULL;
4978 char *encoding = NULL;
4979 struct write_command *write = &cmd->write;
4980 write->expression = matrix_parse_exp (s);
4981 if (!write->expression)
4985 int repetitions = 0;
4986 int record_width = 0;
4987 bool seen_format = false;
4988 while (lex_match (s->lexer, T_SLASH))
4990 if (lex_match_id (s->lexer, "OUTFILE"))
4992 lex_match (s->lexer, T_EQUALS);
4995 fh = fh_parse (s->lexer, FH_REF_FILE, NULL);
4999 else if (lex_match_id (s->lexer, "ENCODING"))
5001 lex_match (s->lexer, T_EQUALS);
5002 if (!lex_force_string (s->lexer))
5006 encoding = ss_xstrdup (lex_tokss (s->lexer));
5010 else if (lex_match_id (s->lexer, "FIELD"))
5012 lex_match (s->lexer, T_EQUALS);
5014 if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX))
5016 write->c1 = lex_integer (s->lexer);
5018 if (!lex_force_match (s->lexer, T_TO)
5019 || !lex_force_int_range (s->lexer, "TO", write->c1, INT_MAX))
5021 write->c2 = lex_integer (s->lexer) + 1;
5024 record_width = write->c2 - write->c1;
5025 if (lex_match (s->lexer, T_BY))
5027 if (!lex_force_int_range (s->lexer, "BY", 1,
5028 write->c2 - write->c1))
5030 by = lex_integer (s->lexer);
5033 if (record_width % by)
5035 msg (SE, _("BY %d does not evenly divide record width %d."),
5043 else if (lex_match_id (s->lexer, "MODE"))
5045 lex_match (s->lexer, T_EQUALS);
5046 if (lex_match_id (s->lexer, "RECTANGULAR"))
5047 write->triangular = false;
5048 else if (lex_match_id (s->lexer, "TRIANGULAR"))
5049 write->triangular = true;
5052 lex_error_expecting (s->lexer, "RECTANGULAR", "TRIANGULAR");
5056 else if (lex_match_id (s->lexer, "HOLD"))
5058 else if (lex_match_id (s->lexer, "FORMAT"))
5062 lex_sbc_only_once ("FORMAT");
5067 lex_match (s->lexer, T_EQUALS);
5069 if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer))
5072 const char *p = lex_tokcstr (s->lexer);
5073 if (c_isdigit (p[0]))
5075 repetitions = atoi (p);
5076 p += strspn (p, "0123456789");
5077 if (!fmt_from_name (p, &write->format))
5079 lex_error (s->lexer, _("Unknown format %s."), p);
5084 else if (!fmt_from_name (p, &write->format))
5086 struct fmt_spec format;
5087 if (!parse_format_specifier (s->lexer, &format))
5089 write->format = format.type;
5090 write->w = format.w;
5091 write->d = format.d;
5096 lex_error_expecting (s->lexer, "OUTFILE", "FIELD", "MODE",
5104 lex_sbc_missing ("FIELD");
5110 if (s->prev_write_file)
5111 fh = fh_ref (s->prev_write_file);
5114 lex_sbc_missing ("OUTFILE");
5118 fh_unref (s->prev_write_file);
5119 s->prev_write_file = fh_ref (fh);
5121 write->wf = write_file_create (s, fh);
5125 free (write->wf->encoding);
5126 write->wf->encoding = encoding;
5130 /* Field width may be specified in multiple ways:
5133 2. The format on FORMAT.
5134 3. The repetition factor on FORMAT.
5136 (2) and (3) are mutually exclusive.
5138 If more than one of these is present, they must agree. If none of them is
5139 present, then free-field format is used.
5141 if (repetitions > record_width)
5143 msg (SE, _("%d repetitions cannot fit in record width %d."),
5144 repetitions, record_width);
5147 int w = (repetitions ? record_width / repetitions
5148 : write->w ? write->w
5153 msg (SE, _("FORMAT specifies %d repetitions with record width %d, "
5154 "which implies field width %d, "
5155 "but BY specifies field width %d."),
5156 repetitions, record_width, w, by);
5158 msg (SE, _("FORMAT specifies field width %d but BY specifies %d."),
5167 matrix_cmd_destroy (cmd);
5172 matrix_cmd_execute_write (struct write_command *write)
5174 gsl_matrix *m = matrix_expr_evaluate (write->expression);
5178 if (write->triangular && m->size1 != m->size2)
5180 msg (SE, _("WRITE with MODE=TRIANGULAR requires a square matrix but "
5181 "the matrix to be written has dimensions %zu×%zu."),
5182 m->size1, m->size2);
5183 gsl_matrix_free (m);
5187 struct dfm_writer *writer = write_file_open (write->wf);
5190 gsl_matrix_free (m);
5194 const struct fmt_settings *settings = settings_get_fmt_settings ();
5195 struct fmt_spec format = {
5196 .type = write->format,
5197 .w = write->w ? write->w : 40,
5200 struct u8_line line = U8_LINE_INITIALIZER;
5201 for (size_t y = 0; y < m->size1; y++)
5203 size_t nx = write->triangular ? y + 1 : m->size2;
5205 for (size_t x = 0; x < nx; x++)
5207 /* XXX string values */
5208 union value v = { .f = gsl_matrix_get (m, y, x) };
5210 ? data_out (&v, NULL, &format, settings)
5211 : data_out_stretchy (&v, NULL, &format, settings, NULL));
5212 size_t len = strlen (s);
5213 int width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
5214 if (width + x0 > write->c2)
5216 dfm_put_record_utf8 (writer, line.s.ss.string, line.s.ss.length);
5217 u8_line_clear (&line);
5220 u8_line_put (&line, x0, x0 + width, s, len);
5223 x0 += write->w ? write->w : width + 1;
5226 dfm_put_record_utf8 (writer, line.s.ss.string, line.s.ss.length);
5227 u8_line_clear (&line);
5229 u8_line_destroy (&line);
5230 dfm_close_writer (writer);
5232 gsl_matrix_free (m);
5235 static struct matrix_cmd *
5236 matrix_parse_get (struct matrix_state *s)
5238 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5239 *cmd = (struct matrix_cmd) {
5242 .user = { .treatment = MGET_ERROR },
5243 .system = { .treatment = MGET_ERROR },
5247 struct get_command *get = &cmd->get;
5248 get->dst = matrix_lvalue_parse (s);
5252 while (lex_match (s->lexer, T_SLASH))
5254 if (lex_match_id (s->lexer, "FILE"))
5256 if (get->variables.n)
5258 lex_error (s->lexer, _("FILE must precede VARIABLES"));
5261 lex_match (s->lexer, T_EQUALS);
5263 fh_unref (get->file);
5264 get->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
5268 else if (lex_match_id (s->lexer, "ENCODING"))
5270 if (get->variables.n)
5272 lex_error (s->lexer, _("ENCODING must precede VARIABLES"));
5275 lex_match (s->lexer, T_EQUALS);
5276 if (!lex_force_string (s->lexer))
5279 free (get->encoding);
5280 get->encoding = ss_xstrdup (lex_tokss (s->lexer));
5284 else if (lex_match_id (s->lexer, "VARIABLES"))
5286 lex_match (s->lexer, T_EQUALS);
5288 struct dictionary *dict = NULL;
5291 dict = dataset_dict (s->dataset);
5292 if (dict_get_var_cnt (dict) == 0)
5294 lex_error (s->lexer, _("GET cannot read empty active file."));
5300 struct casereader *reader = any_reader_open_and_decode (
5301 get->file, get->encoding, &dict, NULL);
5304 casereader_destroy (reader);
5307 struct variable **vars;
5309 bool ok = parse_variables (s->lexer, dict, &vars, &n_vars,
5310 PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH);
5317 string_array_clear (&get->variables);
5318 for (size_t i = 0; i < n_vars; i++)
5319 string_array_append (&get->variables, var_get_name (vars[i]));
5323 else if (lex_match_id (s->lexer, "NAMES"))
5325 lex_match (s->lexer, T_EQUALS);
5326 if (!lex_force_id (s->lexer))
5329 struct substring name = lex_tokss (s->lexer);
5330 get->names = matrix_var_lookup (s, name);
5332 get->names = matrix_var_create (s, name);
5335 else if (lex_match_id (s->lexer, "MISSING"))
5337 lex_match (s->lexer, T_EQUALS);
5338 if (lex_match_id (s->lexer, "ACCEPT"))
5339 get->user.treatment = MGET_ACCEPT;
5340 else if (lex_match_id (s->lexer, "OMIT"))
5341 get->user.treatment = MGET_OMIT;
5342 else if (lex_is_number (s->lexer))
5344 get->user.treatment = MGET_RECODE;
5345 get->user.substitute = lex_number (s->lexer);
5350 lex_error (s->lexer, NULL);
5354 else if (lex_match_id (s->lexer, "SYSMIS"))
5356 lex_match (s->lexer, T_EQUALS);
5357 if (lex_match_id (s->lexer, "OMIT"))
5358 get->user.treatment = MGET_OMIT;
5359 else if (lex_is_number (s->lexer))
5361 get->user.treatment = MGET_RECODE;
5362 get->user.substitute = lex_number (s->lexer);
5367 lex_error (s->lexer, NULL);
5373 lex_error_expecting (s->lexer, "FILE", "VARIABLES", "NAMES",
5374 "MISSING", "SYSMIS");
5381 matrix_cmd_destroy (cmd);
5386 matrix_cmd_execute_get (struct get_command *get)
5388 assert (get->file); /* XXX */
5390 struct dictionary *dict;
5391 struct casereader *reader = any_reader_open_and_decode (
5392 get->file, get->encoding, &dict, NULL);
5396 const struct variable **vars = xnmalloc (
5397 get->variables.n ? get->variables.n : dict_get_var_cnt (dict),
5401 if (get->variables.n)
5403 for (size_t i = 0; i < get->variables.n; i++)
5405 const char *name = get->variables.strings[i];
5406 const struct variable *var = dict_lookup_var (dict, name);
5409 msg (SE, _("GET: Data file does not contain variable %s."),
5415 if (!var_is_numeric (var))
5417 msg (SE, _("GET: Variable %s is not numeric."), name);
5422 vars[n_vars++] = var;
5427 for (size_t i = 0; i < dict_get_var_cnt (dict); i++)
5429 const struct variable *var = dict_get_var (dict, i);
5430 if (!var_is_numeric (var))
5432 msg (SE, _("GET: Variable %s is not numeric."),
5433 var_get_name (var));
5438 vars[n_vars++] = var;
5443 gsl_matrix *m = gsl_matrix_alloc (4, n_vars);
5444 long long int casenum = 1;
5446 for (struct ccase *c = casereader_read (reader); c;
5447 c = casereader_read (reader), casenum++)
5449 if (n_rows >= m->size1)
5451 gsl_matrix *p = gsl_matrix_alloc (m->size1 * 2, n_vars);
5452 for (size_t y = 0; y < n_rows; y++)
5453 for (size_t x = 0; x < n_vars; x++)
5454 gsl_matrix_set (p, y, x, gsl_matrix_get (m, y, x));
5455 gsl_matrix_free (m);
5460 for (size_t x = 0; x < n_vars; x++)
5462 const struct variable *var = vars[x];
5463 double d = case_num (c, var);
5466 if (get->system.treatment == MGET_RECODE)
5467 d = get->system.substitute;
5468 else if (get->system.treatment == MGET_OMIT)
5472 msg (SE, _("GET: Variable %s in case %lld "
5473 "is system-missing."),
5474 var_get_name (var), casenum);
5478 else if (var_is_num_missing (var, d, MV_USER))
5480 if (get->user.treatment == MGET_RECODE)
5481 d = get->user.substitute;
5482 else if (get->user.treatment == MGET_OMIT)
5484 else if (get->user.treatment != MGET_ACCEPT)
5486 msg (SE, _("GET: Variable %s in case %lld has user-missing "
5488 var_get_name (var), casenum, d);
5492 gsl_matrix_set (m, n_rows, x, d);
5500 casereader_destroy (reader);
5504 matrix_lvalue_evaluate_and_assign (get->dst, m);
5507 gsl_matrix_free (m);
5513 match_rowtype (struct lexer *lexer)
5515 static const char *rowtypes[] = {
5516 "COV", "CORR", "MEAN", "STDDEV", "N", "COUNT"
5518 size_t n_rowtypes = sizeof rowtypes / sizeof *rowtypes;
5520 for (size_t i = 0; i < n_rowtypes; i++)
5521 if (lex_match_id (lexer, rowtypes[i]))
5524 lex_error_expecting_array (lexer, rowtypes, n_rowtypes);
5529 parse_var_names (struct lexer *lexer, struct string_array *sa)
5531 lex_match (lexer, T_EQUALS);
5533 string_array_clear (sa);
5535 struct dictionary *dict = dict_create (get_default_encoding ());
5536 dict_create_var_assert (dict, "ROWTYPE_", 8);
5537 dict_create_var_assert (dict, "VARNAME_", 8);
5540 bool ok = parse_DATA_LIST_vars (lexer, dict, &names, &n_names,
5541 PV_NO_DUPLICATE | PV_NO_SCRATCH);
5546 string_array_clear (sa);
5547 sa->strings = names;
5548 sa->n = sa->allocated = n_names;
5554 msave_common_uninit (struct msave_common *common)
5558 fh_unref (common->outfile);
5559 string_array_destroy (&common->variables);
5560 string_array_destroy (&common->fnames);
5561 string_array_destroy (&common->snames);
5566 compare_variables (const char *keyword,
5567 const struct string_array *new,
5568 const struct string_array *old)
5574 msg (SE, _("%s may only be specified on MSAVE if it was specified "
5575 "on the first MSAVE within MATRIX."), keyword);
5578 else if (!string_array_equal_case (old, new))
5580 msg (SE, _("%s must specify the same variables each time within "
5581 "a given MATRIX."), keyword);
5588 static struct matrix_cmd *
5589 matrix_parse_msave (struct matrix_state *s)
5591 struct msave_common common = { .outfile = NULL };
5592 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5593 *cmd = (struct matrix_cmd) { .type = MCMD_MSAVE, .msave = { .expr = NULL } };
5595 struct msave_command *msave = &cmd->msave;
5596 if (lex_token (s->lexer) == T_ID)
5597 msave->varname_ = ss_xstrdup (lex_tokss (s->lexer));
5598 msave->expr = matrix_parse_exp (s);
5602 while (lex_match (s->lexer, T_SLASH))
5604 if (lex_match_id (s->lexer, "TYPE"))
5606 lex_match (s->lexer, T_EQUALS);
5608 msave->rowtype = match_rowtype (s->lexer);
5609 if (!msave->rowtype)
5612 else if (lex_match_id (s->lexer, "OUTFILE"))
5614 lex_match (s->lexer, T_EQUALS);
5616 fh_unref (common.outfile);
5617 common.outfile = fh_parse (s->lexer, FH_REF_FILE, NULL);
5618 if (!common.outfile)
5621 else if (lex_match_id (s->lexer, "VARIABLES"))
5623 if (!parse_var_names (s->lexer, &common.variables))
5626 else if (lex_match_id (s->lexer, "FNAMES"))
5628 if (!parse_var_names (s->lexer, &common.fnames))
5631 else if (lex_match_id (s->lexer, "SNAMES"))
5633 if (!parse_var_names (s->lexer, &common.snames))
5636 else if (lex_match_id (s->lexer, "SPLIT"))
5638 lex_match (s->lexer, T_EQUALS);
5640 matrix_expr_destroy (msave->splits);
5641 msave->splits = matrix_parse_exp (s);
5645 else if (lex_match_id (s->lexer, "FACTOR"))
5647 lex_match (s->lexer, T_EQUALS);
5649 matrix_expr_destroy (msave->factors);
5650 msave->factors = matrix_parse_exp (s);
5651 if (!msave->factors)
5656 lex_error_expecting (s->lexer, "TYPE", "OUTFILE", "VARIABLES",
5657 "FNAMES", "SNAMES", "SPLIT", "FACTOR");
5661 if (!msave->rowtype)
5663 lex_sbc_missing ("TYPE");
5666 common.has_splits = msave->splits || common.snames.n;
5667 common.has_factors = msave->factors || common.fnames.n;
5669 struct msave_common *c = s->common ? s->common : &common;
5670 if (c->fnames.n && !msave->factors)
5672 msg (SE, _("FNAMES requires FACTOR."));
5675 if (c->snames.n && !msave->splits)
5677 msg (SE, _("SNAMES requires SPLIT."));
5680 if (c->has_factors && !common.has_factors)
5682 msg (SE, _("%s is required because it was present on the first "
5683 "MSAVE in this MATRIX command."), "FACTOR");
5686 if (c->has_splits && !common.has_splits)
5688 msg (SE, _("%s is required because it was present on the first "
5689 "MSAVE in this MATRIX command."), "SPLIT");
5695 if (!common.outfile)
5697 lex_sbc_missing ("OUTFILE");
5700 s->common = xmemdup (&common, sizeof common);
5706 bool same = common.outfile == s->common->outfile;
5707 fh_unref (common.outfile);
5710 msg (SE, _("OUTFILE must name the same file on each MSAVE "
5711 "within a single MATRIX command."));
5715 if (!compare_variables ("VARIABLES",
5716 &common.variables, &s->common->variables)
5717 || !compare_variables ("FNAMES", &common.fnames, &s->common->fnames)
5718 || !compare_variables ("SNAMES", &common.snames, &s->common->snames))
5720 msave_common_uninit (&common);
5722 msave->common = s->common;
5723 if (!msave->varname_)
5724 msave->varname_ = xasprintf ("MAT%zu", ++s->common->n_varnames);
5728 msave_common_uninit (&common);
5729 matrix_cmd_destroy (cmd);
5734 matrix_expr_evaluate_vector (struct matrix_expr *e, const char *name)
5736 gsl_matrix *m = matrix_expr_evaluate (e);
5742 msg (SE, _("%s expression must evaluate to vector, "
5743 "not a %zu×%zu matrix."),
5744 name, m->size1, m->size2);
5745 gsl_matrix_free (m);
5749 return matrix_to_vector (m);
5753 msave_add_vars (struct dictionary *d, const struct string_array *vars)
5755 for (size_t i = 0; i < vars->n; i++)
5756 if (!dict_create_var (d, vars->strings[i], 0))
5757 return vars->strings[i];
5761 static struct dictionary *
5762 msave_create_dict (const struct msave_common *common)
5764 struct dictionary *dict = dict_create (get_default_encoding ());
5766 const char *dup_split = msave_add_vars (dict, &common->snames);
5769 msg (SE, _("Duplicate SPLIT variable name %s."), dup_split);
5773 dict_create_var_assert (dict, "ROWTYPE_", 8);
5775 const char *dup_factor = msave_add_vars (dict, &common->fnames);
5778 msg (SE, _("Duplicate or invalid FACTOR variable name %s."), dup_factor);
5782 dict_create_var_assert (dict, "VARNAME_", 8);
5784 const char *dup_var = msave_add_vars (dict, &common->variables);
5787 msg (SE, _("Duplicate or invalid variable name %s."), dup_var);
5799 matrix_cmd_execute_msave (struct msave_command *msave)
5801 struct msave_common *common = msave->common;
5802 gsl_matrix *m = NULL;
5803 gsl_vector *factors = NULL;
5804 gsl_vector *splits = NULL;
5806 m = matrix_expr_evaluate (msave->expr);
5810 if (!common->variables.n)
5811 for (size_t i = 0; i < m->size2; i++)
5812 string_array_append_nocopy (&common->variables,
5813 xasprintf ("COL%zu", i + 1));
5815 if (m->size2 != common->variables.n)
5817 msg (SE, _("Matrix on MSAVE has %zu columns instead of required %zu."),
5818 m->size2, common->variables.n);
5824 factors = matrix_expr_evaluate_vector (msave->factors, "FACTOR");
5828 if (!common->fnames.n)
5829 for (size_t i = 0; i < factors->size; i++)
5830 string_array_append_nocopy (&common->fnames,
5831 xasprintf ("FAC%zu", i + 1));
5833 if (factors->size != common->fnames.n)
5835 msg (SE, _("There are %zu factor variables, "
5836 "but %zu split values were supplied."),
5837 common->fnames.n, factors->size);
5844 splits = matrix_expr_evaluate_vector (msave->splits, "SPLIT");
5848 if (!common->fnames.n)
5849 for (size_t i = 0; i < splits->size; i++)
5850 string_array_append_nocopy (&common->fnames,
5851 xasprintf ("SPL%zu", i + 1));
5853 if (splits->size != common->fnames.n)
5855 msg (SE, _("There are %zu split variables, "
5856 "but %zu split values were supplied."),
5857 common->fnames.n, splits->size);
5862 if (!common->writer)
5864 struct dictionary *dict = msave_create_dict (common);
5868 common->writer = any_writer_open (common->outfile, dict);
5869 if (!common->writer)
5875 common->dict = dict;
5878 for (size_t y = 0; y < m->size1; y++)
5880 struct ccase *c = case_create (dict_get_proto (common->dict));
5883 /* Split variables */
5885 for (size_t i = 0; i < splits->size; i++)
5886 case_data_rw_idx (c, idx++)->f = gsl_vector_get (splits, i);
5889 buf_copy_str_rpad (CHAR_CAST (char *, case_data_rw_idx (c, idx++)->s), 8,
5890 msave->rowtype, ' ');
5894 for (size_t i = 0; i < factors->size; i++)
5895 *case_num_rw_idx (c, idx++) = gsl_vector_get (factors, i);
5898 buf_copy_str_rpad (CHAR_CAST (char *, case_data_rw_idx (c, idx++)->s), 8,
5899 msave->varname_, ' ');
5901 /* Continuous variables. */
5902 for (size_t x = 0; x < m->size2; x++)
5903 case_data_rw_idx (c, idx++)->f = gsl_matrix_get (m, y, x);
5904 casewriter_write (common->writer, c);
5908 gsl_matrix_free (m);
5909 gsl_vector_free (factors);
5910 gsl_vector_free (splits);
5913 static struct matrix_cmd *
5914 matrix_parse_mget (struct matrix_state *s)
5916 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
5917 *cmd = (struct matrix_cmd) { .type = MCMD_MGET, .mget = { .state = s } };
5919 struct mget_command *mget = &cmd->mget;
5923 if (lex_match_id (s->lexer, "FILE"))
5925 lex_match (s->lexer, T_EQUALS);
5927 fh_unref (mget->file);
5928 mget->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
5932 else if (lex_match_id (s->lexer, "TYPE"))
5934 lex_match (s->lexer, T_EQUALS);
5935 while (lex_token (s->lexer) != T_SLASH
5936 && lex_token (s->lexer) != T_ENDCMD)
5938 const char *rowtype = match_rowtype (s->lexer);
5942 stringi_set_insert (&mget->rowtypes, rowtype);
5947 lex_error_expecting (s->lexer, "FILE", "TYPE");
5950 if (lex_token (s->lexer) == T_ENDCMD)
5953 if (!lex_force_match (s->lexer, T_SLASH))
5959 matrix_cmd_destroy (cmd);
5963 static const struct variable *
5964 get_a8_var (const struct dictionary *d, const char *name)
5966 const struct variable *v = dict_lookup_var (d, name);
5969 msg (SE, _("Matrix data file lacks %s variable."), name);
5972 if (var_get_width (v) != 8)
5974 msg (SE, _("%s variable in matrix data file must be "
5975 "8-byte string, but it has width %d."),
5976 name, var_get_width (v));
5983 is_rowtype (const union value *v, const char *rowtype)
5985 struct substring vs = ss_buffer (CHAR_CAST (char *, v->s), 8);
5986 ss_rtrim (&vs, ss_cstr (" "));
5987 return ss_equals_case (vs, ss_cstr (rowtype));
5991 matrix_mget_commit_var (struct ccase **rows, size_t n_rows,
5992 const struct dictionary *d,
5993 const struct variable *rowtype_var,
5994 struct matrix_state *s, size_t si, size_t fi,
5995 size_t cs, size_t cn)
6000 const union value *rowtype_ = case_data (rows[0], rowtype_var);
6001 const char *name_prefix = (is_rowtype (rowtype_, "COV") ? "CV"
6002 : is_rowtype (rowtype_, "CORR") ? "CR"
6003 : is_rowtype (rowtype_, "MEAN") ? "MN"
6004 : is_rowtype (rowtype_, "STDDEV") ? "SD"
6005 : is_rowtype (rowtype_, "N") ? "NC"
6008 struct string name = DS_EMPTY_INITIALIZER;
6009 ds_put_cstr (&name, name_prefix);
6011 ds_put_format (&name, "F%zu", fi);
6013 ds_put_format (&name, "S%zu", si);
6015 struct matrix_var *mv = matrix_var_lookup (s, ds_ss (&name));
6017 mv = matrix_var_create (s, ds_ss (&name));
6020 msg (SW, _("Matrix data file contains variable with existing name %s."),
6025 gsl_matrix *m = gsl_matrix_alloc (n_rows, cn);
6026 size_t n_missing = 0;
6027 for (size_t y = 0; y < n_rows; y++)
6029 for (size_t x = 0; x < cn; x++)
6031 struct variable *var = dict_get_var (d, cs + x);
6032 double value = case_num (rows[y], var);
6033 if (var_is_num_missing (var, value, MV_ANY))
6038 gsl_matrix_set (m, y, x, value);
6043 msg (SE, ngettext ("Matrix data file variable %s contains a missing "
6044 "value, which was treated as zero.",
6045 "Matrix data file variable %s contains %zu missing "
6046 "values, which were treated as zero.", n_missing),
6047 ds_cstr (&name), n_missing);
6052 for (size_t y = 0; y < n_rows; y++)
6053 case_unref (rows[y]);
6057 var_changed (const struct ccase *ca, const struct ccase *cb,
6058 const struct variable *var)
6060 return !value_equal (case_data (ca, var), case_data (cb, var),
6061 var_get_width (var));
6065 vars_changed (const struct ccase *ca, const struct ccase *cb,
6066 const struct dictionary *d,
6067 size_t first_var, size_t n_vars)
6069 for (size_t i = 0; i < n_vars; i++)
6071 const struct variable *v = dict_get_var (d, first_var + i);
6072 if (var_changed (ca, cb, v))
6079 matrix_cmd_execute_mget (struct mget_command *mget)
6081 struct dictionary *d;
6082 struct casereader *r = any_reader_open_and_decode (mget->file, "UTF-8",
6087 const struct variable *rowtype_ = get_a8_var (d, "ROWTYPE_");
6088 const struct variable *varname_ = get_a8_var (d, "VARNAME_");
6089 if (!rowtype_ || !varname_)
6092 if (var_get_dict_index (rowtype_) >= var_get_dict_index (varname_))
6094 msg (SE, _("ROWTYPE_ must precede VARNAME_ in matrix data file."));
6097 if (var_get_dict_index (varname_) + 1 >= dict_get_var_cnt (d))
6099 msg (SE, _("Matrix data file contains no continuous variables."));
6103 for (size_t i = 0; i < dict_get_var_cnt (d); i++)
6105 const struct variable *v = dict_get_var (d, i);
6106 if (v != rowtype_ && v != varname_ && var_get_width (v) != 0)
6109 _("Matrix data file contains unexpected string variable %s."),
6115 /* SPLIT variables. */
6117 size_t sn = var_get_dict_index (rowtype_);
6118 struct ccase *sc = NULL;
6121 /* FACTOR variables. */
6122 size_t fs = var_get_dict_index (rowtype_) + 1;
6123 size_t fn = var_get_dict_index (varname_) - var_get_dict_index (rowtype_) - 1;
6124 struct ccase *fc = NULL;
6127 /* Continuous variables. */
6128 size_t cs = var_get_dict_index (varname_) + 1;
6129 size_t cn = dict_get_var_cnt (d) - cs;
6130 struct ccase *cc = NULL;
6133 struct ccase **rows = NULL;
6134 size_t allocated_rows = 0;
6138 while ((c = casereader_read (r)) != NULL)
6140 bool sd = vars_changed (sc, c, d, ss, sn);
6141 bool fd = sd || vars_changed (fc, c, d, fs, fn);
6142 bool md = fd || !cc || var_changed (cc, c, rowtype_) || var_changed (cc, c, varname_);
6157 matrix_mget_commit_var (rows, n_rows, d, rowtype_,
6158 mget->state, si, fi, cs, cn);
6164 if (n_rows >= allocated_rows)
6165 rows = x2nrealloc (rows, &allocated_rows, sizeof *rows);
6168 matrix_mget_commit_var (rows, n_rows, d, rowtype_,
6169 mget->state, si, fi, cs, cn);
6173 casereader_destroy (r);
6177 matrix_parse_dst_var (struct matrix_state *s, struct matrix_var **varp)
6179 if (!lex_force_id (s->lexer))
6182 *varp = matrix_var_lookup (s, lex_tokss (s->lexer));
6184 *varp = matrix_var_create (s, lex_tokss (s->lexer));
6189 static struct matrix_cmd *
6190 matrix_parse_eigen (struct matrix_state *s)
6192 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6193 *cmd = (struct matrix_cmd) {
6195 .eigen = { .expr = NULL }
6198 struct eigen_command *eigen = &cmd->eigen;
6199 if (!lex_force_match (s->lexer, T_LPAREN))
6201 eigen->expr = matrix_parse_expr (s);
6203 || !lex_force_match (s->lexer, T_COMMA)
6204 || !matrix_parse_dst_var (s, &eigen->evec)
6205 || !lex_force_match (s->lexer, T_COMMA)
6206 || !matrix_parse_dst_var (s, &eigen->eval)
6207 || !lex_force_match (s->lexer, T_RPAREN))
6213 matrix_cmd_destroy (cmd);
6218 matrix_cmd_execute_eigen (struct eigen_command *eigen)
6220 gsl_matrix *A = matrix_expr_evaluate (eigen->expr);
6223 if (!is_symmetric (A))
6225 msg (SE, _("Argument of EIGEN must be symmetric."));
6226 gsl_matrix_free (A);
6230 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc (A->size1);
6231 gsl_matrix *eval = gsl_matrix_alloc (A->size1, 1);
6232 gsl_vector v_eval = to_vector (eval);
6233 gsl_matrix *evec = gsl_matrix_alloc (A->size1, A->size2);
6234 gsl_eigen_symmv (A, &v_eval, evec, w);
6235 gsl_eigen_symmv_free (w);
6237 gsl_eigen_symmv_sort (&v_eval, evec, GSL_EIGEN_SORT_VAL_DESC);
6239 gsl_matrix_free (A);
6241 gsl_matrix_free (eigen->eval->value);
6242 eigen->eval->value = eval;
6244 gsl_matrix_free (eigen->evec->value);
6245 eigen->evec->value = evec;
6248 static struct matrix_cmd *
6249 matrix_parse_setdiag (struct matrix_state *s)
6251 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6252 *cmd = (struct matrix_cmd) {
6253 .type = MCMD_SETDIAG,
6254 .setdiag = { .dst = NULL }
6257 struct setdiag_command *setdiag = &cmd->setdiag;
6258 if (!lex_force_match (s->lexer, T_LPAREN) || !lex_force_id (s->lexer))
6261 setdiag->dst = matrix_var_lookup (s, lex_tokss (s->lexer));
6264 lex_error (s->lexer, _("Unknown variable %s."), lex_tokcstr (s->lexer));
6269 if (!lex_force_match (s->lexer, T_COMMA))
6272 setdiag->expr = matrix_parse_expr (s);
6276 if (!lex_force_match (s->lexer, T_RPAREN))
6282 matrix_cmd_destroy (cmd);
6287 matrix_cmd_execute_setdiag (struct setdiag_command *setdiag)
6289 gsl_matrix *dst = setdiag->dst->value;
6292 msg (SE, _("SETDIAG destination matrix %s is uninitialized."),
6293 setdiag->dst->name);
6297 gsl_matrix *src = matrix_expr_evaluate (setdiag->expr);
6301 size_t n = MIN (dst->size1, dst->size2);
6302 if (is_scalar (src))
6304 double d = to_scalar (src);
6305 for (size_t i = 0; i < n; i++)
6306 gsl_matrix_set (dst, i, i, d);
6308 else if (is_vector (src))
6310 gsl_vector v = to_vector (src);
6311 for (size_t i = 0; i < n && i < v.size; i++)
6312 gsl_matrix_set (dst, i, i, gsl_vector_get (&v, i));
6315 msg (SE, _("SETDIAG argument 2 must be a scalar or a vector, "
6316 "not a %zu×%zu matrix."),
6317 src->size1, src->size2);
6318 gsl_matrix_free (src);
6321 static struct matrix_cmd *
6322 matrix_parse_svd (struct matrix_state *s)
6324 struct matrix_cmd *cmd = xmalloc (sizeof *cmd);
6325 *cmd = (struct matrix_cmd) {
6327 .svd = { .expr = NULL }
6330 struct svd_command *svd = &cmd->svd;
6331 if (!lex_force_match (s->lexer, T_LPAREN))
6333 svd->expr = matrix_parse_expr (s);
6335 || !lex_force_match (s->lexer, T_COMMA)
6336 || !matrix_parse_dst_var (s, &svd->u)
6337 || !lex_force_match (s->lexer, T_COMMA)
6338 || !matrix_parse_dst_var (s, &svd->s)
6339 || !lex_force_match (s->lexer, T_COMMA)
6340 || !matrix_parse_dst_var (s, &svd->v)
6341 || !lex_force_match (s->lexer, T_RPAREN))
6347 matrix_cmd_destroy (cmd);
6352 matrix_cmd_execute_svd (struct svd_command *svd)
6354 gsl_matrix *m = matrix_expr_evaluate (svd->expr);
6358 if (m->size1 >= m->size2)
6361 gsl_matrix *V = gsl_matrix_alloc (A->size2, A->size2);
6362 gsl_matrix *S = gsl_matrix_calloc (A->size2, A->size2);
6363 gsl_vector Sv = gsl_matrix_diagonal (S).vector;
6364 gsl_vector *work = gsl_vector_alloc (A->size2);
6365 gsl_linalg_SV_decomp (A, V, &Sv, work);
6366 gsl_vector_free (work);
6368 matrix_var_set (svd->u, A);
6369 matrix_var_set (svd->s, S);
6370 matrix_var_set (svd->v, V);
6374 gsl_matrix *At = gsl_matrix_alloc (m->size2, m->size1);
6375 gsl_matrix_transpose_memcpy (At, m);
6376 gsl_matrix_free (m);
6378 gsl_matrix *Vt = gsl_matrix_alloc (At->size2, At->size2);
6379 gsl_matrix *St = gsl_matrix_calloc (At->size2, At->size2);
6380 gsl_vector Stv = gsl_matrix_diagonal (St).vector;
6381 gsl_vector *work = gsl_vector_alloc (At->size2);
6382 gsl_linalg_SV_decomp (At, Vt, &Stv, work);
6383 gsl_vector_free (work);
6385 matrix_var_set (svd->v, At);
6386 matrix_var_set (svd->s, St);
6387 matrix_var_set (svd->u, Vt);
6392 matrix_cmd_execute (struct matrix_cmd *cmd)
6397 matrix_cmd_execute_compute (&cmd->compute);
6401 matrix_cmd_execute_print (&cmd->print);
6405 return matrix_cmd_execute_do_if (&cmd->do_if);
6408 matrix_cmd_execute_loop (&cmd->loop);
6415 matrix_cmd_execute_display (&cmd->display);
6419 matrix_cmd_execute_release (&cmd->release);
6423 matrix_cmd_execute_save (&cmd->save);
6427 matrix_cmd_execute_read (&cmd->read);
6431 matrix_cmd_execute_write (&cmd->write);
6435 matrix_cmd_execute_get (&cmd->get);
6439 matrix_cmd_execute_msave (&cmd->msave);
6443 matrix_cmd_execute_mget (&cmd->mget);
6447 matrix_cmd_execute_eigen (&cmd->eigen);
6451 matrix_cmd_execute_setdiag (&cmd->setdiag);
6455 matrix_cmd_execute_svd (&cmd->svd);
6463 matrix_cmds_uninit (struct matrix_cmds *cmds)
6465 for (size_t i = 0; i < cmds->n; i++)
6466 matrix_cmd_destroy (cmds->commands[i]);
6467 free (cmds->commands);
6471 matrix_cmd_destroy (struct matrix_cmd *cmd)
6479 matrix_lvalue_destroy (cmd->compute.lvalue);
6480 matrix_expr_destroy (cmd->compute.rvalue);
6484 matrix_expr_destroy (cmd->print.expression);
6485 free (cmd->print.title);
6486 print_labels_destroy (cmd->print.rlabels);
6487 print_labels_destroy (cmd->print.clabels);
6491 for (size_t i = 0; i < cmd->do_if.n_clauses; i++)
6493 matrix_expr_destroy (cmd->do_if.clauses[i].condition);
6494 matrix_cmds_uninit (&cmd->do_if.clauses[i].commands);
6496 free (cmd->do_if.clauses);
6500 matrix_expr_destroy (cmd->loop.start);
6501 matrix_expr_destroy (cmd->loop.end);
6502 matrix_expr_destroy (cmd->loop.increment);
6503 matrix_expr_destroy (cmd->loop.top_condition);
6504 matrix_expr_destroy (cmd->loop.bottom_condition);
6505 matrix_cmds_uninit (&cmd->loop.commands);
6515 free (cmd->release.vars);
6519 matrix_expr_destroy (cmd->save.expression);
6520 fh_unref (cmd->save.outfile);
6521 string_array_destroy (cmd->save.variables);
6522 matrix_expr_destroy (cmd->save.names);
6523 stringi_set_destroy (&cmd->save.strings);
6527 matrix_lvalue_destroy (cmd->read.dst);
6528 matrix_expr_destroy (cmd->read.size);
6532 matrix_expr_destroy (cmd->write.expression);
6536 matrix_lvalue_destroy (cmd->get.dst);
6537 fh_unref (cmd->get.file);
6538 free (cmd->get.encoding);
6539 string_array_destroy (&cmd->get.variables);
6543 free (cmd->msave.varname_);
6544 matrix_expr_destroy (cmd->msave.expr);
6545 matrix_expr_destroy (cmd->msave.factors);
6546 matrix_expr_destroy (cmd->msave.splits);
6550 fh_unref (cmd->mget.file);
6551 stringi_set_destroy (&cmd->mget.rowtypes);
6555 matrix_expr_destroy (cmd->eigen.expr);
6559 matrix_expr_destroy (cmd->setdiag.expr);
6563 matrix_expr_destroy (cmd->svd.expr);
6569 struct matrix_command_name
6572 struct matrix_cmd *(*parse) (struct matrix_state *);
6575 static const struct matrix_command_name *
6576 matrix_parse_command_name (struct lexer *lexer)
6578 static const struct matrix_command_name commands[] = {
6579 { "COMPUTE", matrix_parse_compute },
6580 { "CALL EIGEN", matrix_parse_eigen },
6581 { "CALL SETDIAG", matrix_parse_setdiag },
6582 { "CALL SVD", matrix_parse_svd },
6583 { "PRINT", matrix_parse_print },
6584 { "DO IF", matrix_parse_do_if },
6585 { "LOOP", matrix_parse_loop },
6586 { "BREAK", matrix_parse_break },
6587 { "READ", matrix_parse_read },
6588 { "WRITE", matrix_parse_write },
6589 { "GET", matrix_parse_get },
6590 { "SAVE", matrix_parse_save },
6591 { "MGET", matrix_parse_mget },
6592 { "MSAVE", matrix_parse_msave },
6593 { "DISPLAY", matrix_parse_display },
6594 { "RELEASE", matrix_parse_release },
6596 static size_t n = sizeof commands / sizeof *commands;
6598 for (const struct matrix_command_name *c = commands; c < &commands[n]; c++)
6599 if (lex_match_phrase (lexer, c->name))
6604 static struct matrix_cmd *
6605 matrix_parse_command (struct matrix_state *s)
6607 size_t nesting_level = SIZE_MAX;
6609 struct matrix_cmd *c = NULL;
6610 const struct matrix_command_name *cmd = matrix_parse_command_name (s->lexer);
6612 lex_error (s->lexer, _("Unknown matrix command."));
6613 else if (!cmd->parse)
6614 lex_error (s->lexer, _("Matrix command %s is not yet implemented."),
6618 nesting_level = output_open_group (
6619 group_item_create_nocopy (utf8_to_title (cmd->name),
6620 utf8_to_title (cmd->name)));
6625 lex_end_of_command (s->lexer);
6626 lex_discard_rest_of_command (s->lexer);
6627 if (nesting_level != SIZE_MAX)
6628 output_close_groups (nesting_level);
6634 cmd_matrix (struct lexer *lexer, struct dataset *ds)
6636 if (!lex_force_match (lexer, T_ENDCMD))
6639 struct matrix_state state = {
6640 .session = dataset_session (ds),
6642 .vars = HMAP_INITIALIZER (state.vars),
6647 while (lex_match (lexer, T_ENDCMD))
6649 if (lex_token (lexer) == T_STOP)
6651 msg (SE, _("Unexpected end of input expecting matrix command."));
6655 if (lex_match_phrase (lexer, "END MATRIX"))
6658 struct matrix_cmd *c = matrix_parse_command (&state);
6661 matrix_cmd_execute (c);
6662 matrix_cmd_destroy (c);
6666 struct matrix_var *var, *next;
6667 HMAP_FOR_EACH_SAFE (var, next, struct matrix_var, hmap_node, &state.vars)
6670 gsl_matrix_free (var->value);
6671 hmap_delete (&state.vars, &var->hmap_node);
6674 hmap_destroy (&state.vars);
6675 fh_unref (state.prev_save_outfile);
6678 dict_unref (state.common->dict);
6679 casewriter_destroy (state.common->writer);
6680 free (state.common);
6682 fh_unref (state.prev_read_file);
6683 for (size_t i = 0; i < state.n_read_files; i++)
6684 read_file_destroy (state.read_files[i]);
6685 free (state.read_files);
6686 fh_unref (state.prev_write_file);
6687 for (size_t i = 0; i < state.n_write_files; i++)
6688 write_file_destroy (state.write_files[i]);
6689 free (state.write_files);