1#ifndef TEST_UTILITIES_INC 2#define TEST_UTILITIES_INC 3 4/* 5 * This file contains functions that are useful when writing tests. 6 * Include it in the test program using #include "test_utilities.inc" 7 */ 8 9#include <igraph.h> 10#include <stdio.h> 11#include <string.h> 12 13/* Print an igraph_real_t value. Be consistent in printing NaN/Inf across platforms. */ 14void print_real(FILE *f, igraph_real_t x, const char *format) { 15 igraph_bool_t g8 = !strcmp(format, "%8g"); 16 if (igraph_finite(x)) { 17 if (x == 0 && signbit(x)) { 18 /* print negative zeros as positive zeros for sake of consistency */ 19 x = +0.0; 20 } 21 fprintf(f, format, x); 22 } else if (igraph_is_nan(x)) { 23 fprintf(f, g8 ? " NaN" : "NaN"); 24 } else if (igraph_is_posinf(x)) { 25 fprintf(f, g8 ? " Inf" : "Inf"); 26 } else if (igraph_is_neginf(x)) { 27 fprintf(f, g8 ? " -Inf" : "-Inf"); 28 } 29} 30 31void print_vector_format(const igraph_vector_t *v, FILE *f, const char *format) { 32 long i, n = igraph_vector_size(v); 33 fprintf(f, "("); 34 for (i=0; i < n; i++) { 35 fprintf(f, " "); 36 print_real(f, VECTOR(*v)[i], format); 37 } 38 fprintf(f, " )\n"); 39} 40 41/* Print elements of a vector. Use parentheses to make it clear when a vector has size zero. */ 42void print_vector(const igraph_vector_t *v) { 43 print_vector_format(v, stdout, "%g"); 44} 45 46/* Round elements of a vector to integers and print them. */ 47/* This is meant to be used when the elements of a vector are integer values. */ 48void print_vector_round(const igraph_vector_t *v) { 49 print_vector_format(v, stdout, "%.f"); 50} 51 52 53/* Print elements of an integer vector */ 54void print_vector_int(const igraph_vector_int_t *v) { 55 long i, n = igraph_vector_int_size(v); 56 printf("("); 57 for (i=0; i < n; i++) { 58 printf(" %" IGRAPH_PRId, VECTOR(*v)[i]); 59 } 60 printf(" )\n"); 61} 62 63 64/* Print elements of a long vector */ 65void print_vector_long(const igraph_vector_long_t *v) { 66 long i, n = igraph_vector_long_size(v); 67 printf("("); 68 for (i=0; i < n; i++) { 69 printf(" %ld", VECTOR(*v)[i]); 70 } 71 printf(" )\n"); 72} 73 74 75/* Print elements of a matrix. Use brackets to make it clear when a vector has size zero. */ 76void print_matrix_format(const igraph_matrix_t *m, FILE *f, const char *format) { 77 long i, j, nrow = igraph_matrix_nrow(m), ncol = igraph_matrix_ncol(m); 78 for (i = 0; i < nrow; i++) { 79 fprintf(f, i == 0 ? "[" : " "); 80 for (j = 0; j < ncol; j++) { 81 fprintf(f, " "); 82 print_real(f, MATRIX(*m, i, j), format); 83 } 84 fprintf(f, i == nrow-1 ? " ]\n" : "\n"); 85 } 86} 87 88void print_matrix(const igraph_matrix_t *m) { 89 print_matrix_format(m, stdout, "%8g"); 90} 91 92/* Round elements of a matrix to integers and print them. */ 93/* This is meant to be used when the elements of a matrix are integer values. */ 94void print_matrix_round(const igraph_matrix_t *m) { 95 print_matrix_format(m, stdout, "%4.f"); 96} 97 98 99/* Print an adjacency list. Use brackets around each vector and also use 100 * brackets around the entire adjacency list to make it clear when the list 101 * is empty. 102 */ 103void print_adjlist(const igraph_adjlist_t *adjlist) { 104 long vcount = igraph_adjlist_size(adjlist); 105 long i; 106 107 printf("{\n"); 108 for (i = 0; i < vcount; ++i) { 109 printf(" %ld: ", i); 110 print_vector_int(igraph_adjlist_get(adjlist, i)); 111 } 112 printf("}\n"); 113} 114 115/* Print a graph. Use brackets to make it obvious when the edge list is empty. */ 116void print_graph(const igraph_t *graph) { 117 long ecount = igraph_ecount(graph); 118 long vcount = igraph_vcount(graph); 119 long i; 120 121 printf("directed: %s\n", igraph_is_directed(graph) ? "true" : "false"); 122 printf("vcount: %ld\n", vcount); 123 printf("edges: {\n"); 124 for (i=0; i < ecount; ++i) 125 printf("%" IGRAPH_PRId " %" IGRAPH_PRId "\n", IGRAPH_FROM(graph, i), IGRAPH_TO(graph, i)); 126 printf("}\n"); 127} 128 129/* Print an incidence list. Use brackets around each vector and also use 130 * brackets around the entire incidence list to make it clear when the list 131 * is empty. 132 */ 133void print_inclist(const igraph_inclist_t *inclist) { 134 long vcount = igraph_inclist_size(inclist); 135 long i; 136 137 printf("{\n"); 138 for (i = 0; i < vcount; ++i) { 139 printf(" %ld: ", i); 140 print_vector_int(igraph_inclist_get(inclist, i)); 141 } 142 printf("}\n"); 143} 144 145/* Print a lazy adjacency list. Use brackets around each vector and also use 146 * brackets around the entire lazy adjacency list to make it clear when the list 147 * is empty. 148 */ 149void print_lazy_adjlist(igraph_lazy_adjlist_t *adjlist) { 150 long vcount = igraph_lazy_adjlist_size(adjlist); 151 long i; 152 153 printf("{\n"); 154 for (i = 0; i < vcount; ++i) { 155 printf(" %ld: ", i); 156 print_vector_int(igraph_lazy_adjlist_get(adjlist, i)); 157 } 158 printf("}\n"); 159} 160 161/* Print a lazy incidence list. Use brackets around each vector and also use 162 * brackets around the entire incidence list to make it clear when the list 163 * is empty. 164 */ 165void print_lazy_inclist(igraph_lazy_inclist_t *inclist) { 166 long vcount = igraph_lazy_inclist_size(inclist); 167 long i; 168 169 printf("{\n"); 170 for (i = 0; i < vcount; ++i) { 171 printf(" %ld: ", i); 172 print_vector_int(igraph_lazy_inclist_get(inclist, i)); 173 } 174 printf("}\n"); 175} 176 177/* Edge comparisong function used for sorting in print_graph_canon(). */ 178int edge_compare(const void *e1, const void *e2) { 179 const igraph_real_t *edge1 = (igraph_real_t *) e1, *edge2 = (igraph_real_t *) e2; 180 if (edge1[0] < edge2[0]) { 181 return -1; 182 } else if (edge1[0] > edge2[0]) { 183 return 1; 184 } else if (edge1[1] < edge2[1]) { 185 return -1; 186 } else if (edge1[1] > edge2[1]) { 187 return 1; 188 } else { 189 return 0; 190 } 191} 192 193/* Print a graph using a sorted edge list. Other than sorting (i.e. canonicalizing) the edge list, 194 * this function is identical to print_graph(). */ 195void print_graph_canon(const igraph_t *graph) { 196 long ecount = igraph_ecount(graph); 197 long vcount = igraph_vcount(graph); 198 long i; 199 igraph_vector_t edges; 200 201 printf("directed: %s\n", igraph_is_directed(graph) ? "true" : "false"); 202 printf("vcount: %ld\n", vcount); 203 printf("edges: {\n"); 204 205 igraph_vector_init(&edges, 0); 206 igraph_get_edgelist(graph, &edges, 0); 207 208 /* If the graph is undirected, we make sure that the first vertex of undirected edges 209 * is always the one with the lower ID. */ 210 if (! igraph_is_directed(graph)) { 211 for (i=0; i < ecount; ++i) { 212 if (VECTOR(edges)[2*i] > VECTOR(edges)[2*i+1]) { 213 igraph_real_t tmp = VECTOR(edges)[2*i]; 214 VECTOR(edges)[2*i] = VECTOR(edges)[2*i+1]; 215 VECTOR(edges)[2*i+1] = tmp; 216 } 217 } 218 } 219 220 /* Sort the edge list */ 221 igraph_qsort(&VECTOR(edges)[0], ecount, 2*sizeof(igraph_real_t), &edge_compare); 222 223 for (i=0; i < ecount; ++i) { 224 printf("%ld %ld\n", (long) VECTOR(edges)[2*i], (long) VECTOR(edges)[2*i+1]); 225 } 226 227 igraph_vector_destroy(&edges); 228 229 printf("}\n"); 230} 231 232/* Print a vector, ensuring that the first nonzero element is positive. */ 233void print_vector_first_nonzero_element_positive(const igraph_vector_t *vector, const char* format) { 234 igraph_vector_t copy; 235 long i, n; 236 237 igraph_vector_copy(©, vector); 238 239 n = igraph_vector_size(©); 240 241 for (i = 0; i < n; i++) { 242 if (VECTOR(copy)[i] < 0) { 243 for (; i < n; i++) { 244 if (VECTOR(copy)[i] != 0) { 245 VECTOR(copy)[i] *= -1; 246 } 247 } 248 break; 249 } else if (VECTOR(copy)[i] > 0) { 250 break; 251 } 252 } 253 254 igraph_vector_printf(©, format); 255 igraph_vector_destroy(©); 256} 257 258/* Print a complex vector, ensuring that the first element with nonzero real 259 * part has a positive real part. */ 260void print_vector_complex_first_nonzero_real_part_positive(const igraph_vector_complex_t *vector) { 261 igraph_vector_complex_t copy; 262 long i, n; 263 264 igraph_vector_complex_copy(©, vector); 265 266 n = igraph_vector_complex_size(©); 267 268 for (i = 0; i < n; i++) { 269 if (IGRAPH_REAL(VECTOR(copy)[i]) < 0) { 270 for (; i < n; i++) { 271 if (IGRAPH_REAL(VECTOR(copy)[i]) != 0) { 272 IGRAPH_REAL(VECTOR(copy)[i]) *= -1; 273 } 274 if (IGRAPH_IMAG(VECTOR(copy)[i]) != 0) { 275 IGRAPH_IMAG(VECTOR(copy)[i]) *= -1; 276 } 277 } 278 break; 279 } else if (IGRAPH_REAL(VECTOR(copy)[i]) > 0) { 280 break; 281 } 282 } 283 284 igraph_vector_complex_print(©); 285 igraph_vector_complex_destroy(©); 286} 287 288/* Print a matrix, ensuring that the first nonzero element in each column is 289 * positive. */ 290void print_matrix_first_row_positive(const igraph_matrix_t *matrix, const char* format) { 291 igraph_matrix_t copy; 292 long i, j, nrow, ncol; 293 294 igraph_matrix_copy(©, matrix); 295 296 nrow = igraph_matrix_nrow(©); 297 ncol = igraph_matrix_ncol(©); 298 299 for (i = 0; i < ncol; i++) { 300 for (j = 0; j < nrow; j++) { 301 if (MATRIX(copy, j, i) < 0) { 302 for (; j < nrow; j++) { 303 if (MATRIX(copy, j, i) != 0) { 304 MATRIX(copy, j, i) *= -1; 305 } 306 } 307 break; 308 } else if (MATRIX(copy, j, i) > 0) { 309 break; 310 } 311 } 312 } 313 314 igraph_matrix_printf(©, format); 315 igraph_matrix_destroy(©); 316} 317 318/* Print a complex matrix, ensuring that the first element with nonzero real 319 * part in each column has a positive real part. */ 320void print_matrix_complex_first_row_positive(const igraph_matrix_complex_t *matrix) { 321 igraph_matrix_complex_t copy; 322 long i, j, nrow, ncol; 323 igraph_complex_t z; 324 char buf[256]; 325 size_t len; 326 327 igraph_matrix_complex_copy(©, matrix); 328 329 nrow = igraph_matrix_complex_nrow(©); 330 ncol = igraph_matrix_complex_ncol(©); 331 332 for (i = 0; i < ncol; i++) { 333 for (j = 0; j < nrow; j++) { 334 if (IGRAPH_REAL(MATRIX(copy, j, i)) < 0) { 335 for (; j < nrow; j++) { 336 if (IGRAPH_REAL(MATRIX(copy, j, i)) != 0) { 337 IGRAPH_REAL(MATRIX(copy, j, i)) *= -1; 338 } 339 if (IGRAPH_IMAG(MATRIX(copy, j, i)) != 0) { 340 IGRAPH_IMAG(MATRIX(copy, j, i)) *= -1; 341 } 342 } 343 break; 344 } else if (IGRAPH_REAL(MATRIX(copy, j, i)) > 0) { 345 break; 346 } 347 } 348 } 349 350 for (i = 0; i < nrow; i++) { 351 for (j = 0; j < ncol; j++) { 352 z = MATRIX(copy, i, j); 353 if (j != 0) { 354 putchar(' '); 355 } 356 357 snprintf(buf, sizeof(buf), "%g%+gi", IGRAPH_REAL(z), IGRAPH_IMAG(z)); 358 len = strlen(buf); 359 360 /* ensure that we don't print -0 in the imaginary part */ 361 if (len > 3 && buf[len-3] == '-' && buf[len-2] == '0' && buf[len-1] == 'i') { 362 buf[len-3] = '+'; 363 } 364 365 /* ensure that we don't print -0 in the real part either */ 366 if (buf[0] == '-' && buf[1] == '0' && (buf[2] == '+' || buf[2] == '-')) { 367 printf("%s", buf + 1); 368 } else { 369 printf("%s", buf); 370 } 371 } 372 printf("\n"); 373 } 374 375 igraph_matrix_complex_destroy(©); 376} 377 378void matrix_init_int_row_major(igraph_matrix_t *mat, int nrow, int ncol, int* elem) { 379 int c, r; 380 int i_elem = 0; 381 igraph_matrix_init(mat, nrow, ncol); 382 for (r = 0; r < nrow; r++) { 383 for (c = 0; c < ncol; c++) { 384 MATRIX(*mat, r, c) = elem[i_elem]; 385 i_elem++; 386 } 387 } 388} 389 390void matrix_init_real_row_major(igraph_matrix_t *mat, int nrow, int ncol, igraph_real_t* elem) { 391 int c, r; 392 int i_elem = 0; 393 igraph_matrix_init(mat, nrow, ncol); 394 for (r = 0; r < nrow; r++) { 395 for (c = 0; c < ncol; c++) { 396 MATRIX(*mat, r, c) = elem[i_elem]; 397 i_elem++; 398 } 399 } 400} 401 402void matrix_chop(igraph_matrix_t *mat, igraph_real_t cutoff) { 403 int i; 404 for (i = 0; i < igraph_matrix_nrow(mat) * igraph_matrix_ncol(mat); i++) { 405 if (fabs(VECTOR(mat->data)[i]) < cutoff) { 406 VECTOR(mat->data)[i] = 0; 407 } 408 } 409} 410 411void print_spmatrix(igraph_spmatrix_t *m) { 412 long int i, j; 413 for (i = 0; i < igraph_spmatrix_nrow(m); i++) { 414 for (j = 0; j < igraph_spmatrix_ncol(m); j++) { 415 printf(" %8g", igraph_spmatrix_e(m, i, j)); 416 } 417 printf("\n"); 418 } 419} 420 421#define VERIFY_FINALLY_STACK() \ 422 if (!IGRAPH_FINALLY_STACK_EMPTY) { \ 423 printf( \ 424 "%s:%d : " \ 425 "Finally stack is not empty (stack size is %d). " \ 426 "Check that the number in IGRAPH_FINALLY_CLEAN matches the IGRAPH_FINALLY count.\n", \ 427 IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_FINALLY_STACK_SIZE()); \ 428 abort(); \ 429 } 430 431/* Run a test in a separate function; return the return value of the function 432 * if it is nonzero. Also verify the FINALLY stack and bail out if it is not 433 * empty. Needs an integer variable named 'retval' in the local context. */ 434#define RUN_TEST(func) \ 435 { \ 436 retval = func(); \ 437 if (retval) { \ 438 return retval; \ 439 } \ 440 VERIFY_FINALLY_STACK(); \ 441 } 442 443#define CHECK_ERROR(funcall, expected_err) \ 444 do { \ 445 igraph_error_handler_t *handler; \ 446 handler = igraph_set_error_handler(igraph_error_handler_ignore); \ 447 IGRAPH_ASSERT(funcall == expected_err); \ 448 igraph_set_error_handler(handler); \ 449 } while (0) 450 451#endif /* TEST_UTILITIES_INC */ 452