1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 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/>. */
17 /* This is a test program for the sparse array routines defined
18 in sparse-xarray.c. */
31 #include <libpspp/argv-parser.h>
32 #include <libpspp/assertion.h>
33 #include <libpspp/hash-functions.h>
34 #include <libpspp/model-checker.h>
35 #include <libpspp/sparse-xarray.h>
36 #include <libpspp/str.h>
42 /* Maximum size of sparse_xarray supported for model checking
47 /* Test parameters. */
50 /* Controlling the test state space. */
51 int n_columns
; /* Number of columns in each row. */
52 int max_rows
; /* Maximum number of rows. */
53 int max_memory_rows
; /* Max rows before writing to disk. */
54 unsigned char n_values
; /* Number of unique cell values. */
55 int n_xarrays
; /* Number of sparse_xarrays in state. */
57 /* Types of operations to perform. */
58 bool write_cells
; /* Write to individual cells. */
59 bool write_rows
; /* Write whole rows. */
60 bool write_columns
; /* Write whole columns. */
61 bool copy_within_xarray
; /* Copy column ranges in a single xarray. */
66 struct sparse_xarray
*xarrays
[2];
70 test_state_destroy (const struct test_params
*params
, struct test_state
*ts
)
74 for (i
= 0; i
< params
->n_xarrays
; i
++)
75 sparse_xarray_destroy (ts
->xarrays
[i
]);
79 static struct test_state
*
80 test_state_clone (const struct test_params
*params
,
81 const struct test_state
*ots
)
83 struct test_state
*ts
;
86 ts
= xmalloc (sizeof *ts
);
87 for (i
= 0; i
< params
->n_xarrays
; i
++)
89 ts
->xarrays
[i
] = sparse_xarray_clone (ots
->xarrays
[i
]);
90 if (ts
->xarrays
[i
] == NULL
)
98 uint8_t data
[MAX_ROWS
][MAX_COLS
];
99 bool contains_row
[MAX_ROWS
];
104 struct xarray_model models
[2];
107 /* Extracts the contents of TS into TM. */
109 test_model_extract (const struct test_params
*params
,
110 const struct test_state
*ts
, struct test_model
*tm
)
114 for (i
= 0; i
< params
->n_xarrays
; i
++)
116 const struct sparse_xarray
*sx
= ts
->xarrays
[i
];
117 struct xarray_model
*model
= &tm
->models
[i
];
118 size_t n_columns
= sparse_xarray_get_n_columns (sx
);
119 size_t n_rows
= sparse_xarray_get_n_rows (sx
);
122 assert (n_rows
< MAX_ROWS
);
123 assert (n_columns
< MAX_COLS
);
124 for (row
= 0; row
< params
->max_rows
; row
++)
126 model
->contains_row
[row
] = sparse_xarray_contains_row (sx
, row
);
127 if (!sparse_xarray_read (sx
, row
, 0, n_columns
, model
->data
[row
]))
133 /* Checks that test state TS matches the test model TM and
134 reports any mismatches via mc_error. Then, adds SX to MC as a
137 check_state (struct mc
*mc
, struct test_state
*ts
, const struct test_model
*tm
)
139 const struct test_params
*params
= mc_get_aux (mc
);
140 int n_columns
= params
->n_columns
;
144 for (i
= 0; i
< params
->n_xarrays
; i
++)
146 const struct xarray_model
*model
= &tm
->models
[i
];
147 const struct sparse_xarray
*sx
= ts
->xarrays
[i
];
152 assert (n_columns
< MAX_COLS
);
154 /* Check row count. */
156 for (row
= 0; row
< params
->max_rows
; row
++)
157 if (model
->contains_row
[row
])
159 if (n_rows
!= sparse_xarray_get_n_rows (sx
))
160 mc_error (mc
, "xarray %d: row count (%zu) does not match expected "
161 "(%d)", i
, sparse_xarray_get_n_rows (sx
), n_rows
);
163 /* Check row containment. */
164 for (row
= 0; row
< params
->max_rows
; row
++)
166 bool contains
= sparse_xarray_contains_row (sx
, row
);
167 if (contains
&& !model
->contains_row
[row
])
168 mc_error (mc
, "xarray %d: row %d is contained by sparse_xarray "
169 "but should not be", i
, row
);
170 else if (!contains
&& model
->contains_row
[row
])
171 mc_error (mc
, "xarray %d: row %d is not contained by "
172 "sparse_xarray but should be", i
, row
);
175 /* Check contents. */
177 for (row
= 0; row
< params
->max_rows
; row
++)
179 unsigned char data
[MAX_COLS
];
181 if (!sparse_xarray_read (sx
, row
, 0, n_columns
, data
))
183 for (col
= 0; col
< params
->n_columns
; col
++)
184 if (data
[col
] != model
->data
[row
][col
])
186 mc_error (mc
, "xarray %d: element %d,%d (of %d,%d) "
187 "differs: %d should be %d",
188 i
, row
, col
, n_rows
, n_columns
, data
[col
],
189 model
->data
[row
][col
]);
198 mc_error (mc
, "xarray %d: expected:", i
);
200 for (row
= 0; row
< params
->max_rows
; row
++)
203 for (col
= 0; col
< n_columns
; col
++)
204 ds_put_format (&ds
, " %d", model
->data
[row
][col
]);
205 mc_error (mc
, "xarray %d: row %d:%s", i
, row
, ds_cstr (&ds
));
208 mc_error (mc
, "xarray %d: actual:", i
);
210 for (row
= 0; row
< params
->max_rows
; row
++)
212 unsigned char data
[MAX_COLS
];
214 if (!sparse_xarray_read (sx
, row
, 0, n_columns
, data
))
218 for (col
= 0; col
< n_columns
; col
++)
219 ds_put_format (&ds
, " %d", data
[col
]);
220 mc_error (mc
, "xarray %d: row %d:%s", i
, row
, ds_cstr (&ds
));
228 for (i
= 0; i
< params
->n_xarrays
; i
++)
229 hash
= sparse_xarray_model_checker_hash (ts
->xarrays
[i
], hash
);
230 if (mc_discard_dup_state (mc
, hash
))
231 test_state_destroy (params
, ts
);
233 mc_add_state (mc
, ts
);
237 next_data (unsigned char *data
, int n
, int n_values
)
240 for (i
= n
- 1; i
>= 0; i
--)
243 if (data
[i
] < n_values
)
250 struct copy_columns_params
252 int n
; /* Number of columns to copy. */
253 int src
; /* Offset of first source column. */
254 int dst
; /* Offset of first destination column. */
258 copy_columns (const void *src_
, void *dst_
, void *copy_
)
260 const struct copy_columns_params
*copy
= copy_
;
261 const uint8_t *src
= src_
;
264 memmove (dst
+ copy
->dst
, src
+ copy
->src
, copy
->n
);
268 /* "init" function for struct mc_class. */
270 sparse_xarray_mc_init (struct mc
*mc
)
272 struct test_params
*params
= mc_get_aux (mc
);
273 struct test_state
*ts
;
274 struct test_model tm
;
277 mc_name_operation (mc
, "empty sparse_xarray with n_columns=%d, "
278 "max_memory_rows=%d",
279 params
->n_columns
, params
->max_memory_rows
);
280 ts
= xmalloc (sizeof *ts
);
281 for (i
= 0; i
< params
->n_xarrays
; i
++)
282 ts
->xarrays
[i
] = sparse_xarray_create (params
->n_columns
,
283 params
->max_memory_rows
);
284 memset (&tm
, 0, sizeof tm
);
285 check_state (mc
, ts
, &tm
);
288 /* "mutate" function for struct mc_class. */
290 sparse_xarray_mc_mutate (struct mc
*mc
, const void *ots_
)
292 struct test_params
*params
= mc_get_aux (mc
);
293 size_t n_columns
= params
->n_columns
;
294 const struct test_state
*ots
= ots_
;
295 struct test_model otm
;
298 test_model_extract (params
, ots
, &otm
);
299 for (i
= 0; i
< params
->n_xarrays
; i
++)
302 int row
, col
, n
, src
, dst
;
304 /* Write all possible values to each possible single cell. */
305 if (params
->write_cells
)
306 for (row
= 0; row
< params
->max_rows
; row
++)
307 for (col
= 0; col
< n_columns
; col
++)
308 for (value
= 0; value
< params
->n_values
; value
++)
309 if (mc_include_state (mc
))
311 struct test_state
*ts
= test_state_clone (params
, ots
);
312 struct sparse_xarray
*sx
= ts
->xarrays
[i
];
313 struct test_model tm
= otm
;
314 struct xarray_model
*model
= &tm
.models
[i
];
316 mc_name_operation (mc
, "xarray %d: set (%d,%d) to %d",
318 if (!sparse_xarray_write (sx
, row
, col
, 1, &value
))
320 model
->data
[row
][col
] = value
;
321 model
->contains_row
[row
] = true;
322 check_state (mc
, ts
, &tm
);
325 /* Write all possible row contents to each row. */
326 if (params
->write_rows
)
327 for (row
= 0; row
< params
->max_rows
; row
++)
329 struct test_model tm
= otm
;
330 struct xarray_model
*model
= &tm
.models
[i
];
332 memset (model
->data
[row
], 0, n_columns
);
333 model
->contains_row
[row
] = true;
336 if (mc_include_state (mc
))
338 struct test_state
*ts
= test_state_clone (params
, ots
);
339 struct sparse_xarray
*sx
= ts
->xarrays
[i
];
340 char row_string
[MAX_COLS
+ 1];
342 mc_name_operation (mc
, "xarray %d: set row %d to %s",
344 for (col
= 0; col
< n_columns
; col
++)
346 value
= model
->data
[row
][col
];
347 row_string
[col
] = value
< 10 ? '0' + value
: '*';
349 row_string
[n_columns
] = '\0';
350 if (!sparse_xarray_write (sx
, row
, 0, n_columns
,
353 check_state (mc
, ts
, &tm
);
356 while (next_data (model
->data
[row
], n_columns
, params
->n_values
));
359 /* Write all possible values to each possible column. */
360 if (params
->write_columns
)
361 for (col
= 0; col
< n_columns
; col
++)
362 for (value
= 0; value
< params
->n_values
; value
++)
363 if (mc_include_state (mc
))
365 struct test_state
*ts
= test_state_clone (params
, ots
);
366 struct sparse_xarray
*sx
= ts
->xarrays
[i
];
367 struct test_model tm
= otm
;
368 struct xarray_model
*model
= &tm
.models
[i
];
370 mc_name_operation (mc
, "xarray %d: write value %d to "
371 "column %d", i
, value
, col
);
372 if (!sparse_xarray_write_columns (sx
, col
, 1, &value
))
374 for (row
= 0; row
< params
->max_rows
; row
++)
375 model
->data
[row
][col
] = value
;
376 check_state (mc
, ts
, &tm
);
379 /* Copy all possible column ranges within a single sparse_xarray. */
380 if (params
->copy_within_xarray
)
381 for (n
= 1; n
<= n_columns
; n
++)
382 for (src
= 0; src
<= n_columns
- n
; src
++)
383 for (dst
= 0; dst
<= n_columns
- n
; dst
++)
384 if (mc_include_state (mc
))
386 struct copy_columns_params copy_aux
;
387 struct test_state
*ts
= test_state_clone (params
, ots
);
388 struct sparse_xarray
*sx
= ts
->xarrays
[i
];
389 struct test_model tm
= otm
;
390 struct xarray_model
*model
= &tm
.models
[i
];
392 mc_name_operation (mc
, "xarray %d: copy %d columns from "
393 "offset %d to offset %d", i
, n
, src
, dst
);
398 if (!sparse_xarray_copy (sx
, sx
, copy_columns
, ©_aux
))
401 for (row
= 0; row
< params
->max_rows
; row
++)
402 memmove (&model
->data
[row
][dst
],
403 &model
->data
[row
][src
], n
);
405 check_state (mc
, ts
, &tm
);
409 if (params
->n_xarrays
== 2)
411 int row
, n
, src
, dst
;
413 /* Copy all possible column ranges from xarrays[0] to xarrays[1]. */
414 for (n
= 1; n
<= n_columns
; n
++)
415 for (src
= 0; src
<= n_columns
- n
; src
++)
416 for (dst
= 0; dst
<= n_columns
- n
; dst
++)
417 if (mc_include_state (mc
))
419 struct copy_columns_params copy_aux
;
420 struct test_state
*ts
= test_state_clone (params
, ots
);
421 struct test_model tm
= otm
;
423 mc_name_operation (mc
, "copy %d columns from offset %d in "
424 "xarray 0 to offset %d in xarray 1",
430 if (!sparse_xarray_copy (ts
->xarrays
[0], ts
->xarrays
[1],
431 copy_columns
, ©_aux
))
434 for (row
= 0; row
< params
->max_rows
; row
++)
436 if (tm
.models
[0].contains_row
[row
])
437 tm
.models
[1].contains_row
[row
] = true;
438 memmove (&tm
.models
[1].data
[row
][dst
],
439 &tm
.models
[0].data
[row
][src
], n
);
442 check_state (mc
, ts
, &tm
);
447 /* "destroy" function for struct mc_class. */
449 sparse_xarray_mc_destroy (const struct mc
*mc UNUSED
, void *ts_
)
451 struct test_params
*params
= mc_get_aux (mc
);
452 struct test_state
*ts
= ts_
;
454 test_state_destroy (params
, ts
);
460 printf ("%s, for testing the sparse_xarray implementation.\n"
461 "Usage: %s [OPTION]...\n"
462 "\nTest state space parameters (min...max, default):\n"
463 " --columns=N Number of columns per row (0...5, 3)\n"
464 " --max-rows=N Maximum number of rows (0...5, 3)\n"
465 " --max-memory-rows=N Max rows before paging to disk (0...5, 3)\n"
466 " --values=N Number of unique cell values (1...254, 3)\n"
467 " --xarrays=N Number of xarrays at a time (1...2, 1)\n"
468 "\nTest operation parameters:\n"
469 " --no-write-cells Do not write individual cells\n"
470 " --no-write-rows Do not write whole rows\n"
471 " --no-write-columns Do not write whole columns\n"
472 " --no-copy-columns Do not copy column ranges in an xarray\n",
473 program_name
, program_name
);
475 printf ("\nOther options:\n"
476 " --help Display this help message\n"
477 "\nReport bugs to <%s>\n", PACKAGE_BUGREPORT
);
490 OPT_NO_WRITE_COLUMNS
,
493 N_SPARSE_XARRAY_OPTIONS
496 static struct argv_option sparse_xarray_argv_options
[N_SPARSE_XARRAY_OPTIONS
] =
498 {"columns", 0, required_argument
, OPT_COLUMNS
},
499 {"max-rows", 0, required_argument
, OPT_MAX_ROWS
},
500 {"max-memory-rows", 0, required_argument
, OPT_MAX_MEMORY_ROWS
},
501 {"values", 0, required_argument
, OPT_VALUES
},
502 {"xarrays", 0, required_argument
, OPT_XARRAYS
},
503 {"no-write-cells", 0, no_argument
, OPT_NO_WRITE_CELLS
},
504 {"no-write-rows", 0, no_argument
, OPT_NO_WRITE_ROWS
},
505 {"no-write-columns", 0, no_argument
, OPT_NO_WRITE_COLUMNS
},
506 {"no-copy-columns", 0, no_argument
, OPT_NO_COPY_COLUMNS
},
507 {"help", 'h', no_argument
, OPT_HELP
},
511 sparse_xarray_option_callback (int id
, void *params_
)
513 struct test_params
*params
= params_
;
517 params
->n_columns
= atoi (optarg
);
521 params
->max_rows
= atoi (optarg
);
524 case OPT_MAX_MEMORY_ROWS
:
525 params
->max_memory_rows
= atoi (optarg
);
529 params
->n_values
= atoi (optarg
);
533 params
->n_xarrays
= atoi (optarg
);
536 case OPT_NO_WRITE_CELLS
:
537 params
->write_cells
= false;
540 case OPT_NO_WRITE_ROWS
:
541 params
->write_rows
= false;
544 case OPT_NO_WRITE_COLUMNS
:
545 params
->write_columns
= false;
548 case OPT_NO_COPY_COLUMNS
:
549 params
->copy_within_xarray
= false;
562 main (int argc
, char *argv
[])
564 static const struct mc_class sparse_xarray_mc_class
=
566 sparse_xarray_mc_init
,
567 sparse_xarray_mc_mutate
,
568 sparse_xarray_mc_destroy
,
571 struct test_params params
;
572 struct mc_options
*options
;
573 struct mc_results
*results
;
574 struct argv_parser
*parser
;
578 set_program_name (argv
[0]);
580 /* Default parameters. */
581 params
.n_columns
= 3;
583 params
.max_memory_rows
= 3;
585 params
.n_xarrays
= 1;
586 params
.write_cells
= true;
587 params
.write_rows
= true;
588 params
.write_columns
= true;
589 params
.copy_within_xarray
= true;
591 /* Parse command line. */
592 parser
= argv_parser_create ();
593 options
= mc_options_create ();
594 mc_options_register_argv_parser (options
, parser
);
595 argv_parser_add_options (parser
, sparse_xarray_argv_options
,
596 N_SPARSE_XARRAY_OPTIONS
,
597 sparse_xarray_option_callback
, ¶ms
);
598 if (!argv_parser_run (parser
, argc
, argv
))
600 argv_parser_destroy (parser
);
601 verbosity
= mc_options_get_verbosity (options
);
603 /* Force parameters into allowed ranges. */
604 params
.n_columns
= MAX (0, MIN (params
.n_columns
, MAX_COLS
));
605 params
.max_rows
= MAX (0, MIN (params
.max_rows
, MAX_ROWS
));
606 params
.max_memory_rows
= MAX (0, MIN (params
.max_memory_rows
,
608 params
.n_values
= MIN (254, MAX (1, params
.n_values
));
609 params
.n_xarrays
= MAX (1, MIN (2, params
.n_xarrays
));
610 mc_options_set_aux (options
, ¶ms
);
611 results
= mc_run (&sparse_xarray_mc_class
, options
);
613 /* Output results. */
614 success
= (mc_results_get_stop_reason (results
) != MC_MAX_ERROR_COUNT
615 && mc_results_get_stop_reason (results
) != MC_INTERRUPTED
);
616 if (verbosity
> 0 || !success
)
618 printf ("Parameters: "
619 "--columns=%d --max-rows=%d --max-memory-rows=%d --values=%d "
621 params
.n_columns
, params
.max_rows
, params
.max_memory_rows
,
622 params
.n_values
, params
.n_xarrays
);
623 if (!params
.write_cells
)
624 printf (" --no-write-cells");
625 if (!params
.write_rows
)
626 printf (" --no-write-rows");
627 if (!params
.write_columns
)
628 printf (" --no-write-columns");
629 if (!params
.copy_within_xarray
)
630 printf (" --no-copy-columns");
632 mc_results_print (results
, stdout
);
634 mc_results_destroy (results
);
636 return success
? 0 : EXIT_FAILURE
;