diff --git a/dir-locals.el b/dir-locals.el new file mode 100644 index 0000000000000000000000000000000000000000..b44beca9c9609683ab1e996c8193c4b2edbcd8c5 --- /dev/null +++ b/dir-locals.el @@ -0,0 +1,105 @@ +;; C style for Emacs, to assist in following DAGuE coding conventions (originally from PETSc project) +((nil . ((indent-tabs-mode . nil) + (tab-width . 8) + (show-trailing-whitespace . t))) + (c-mode . ((c-tab-always-indent . t) + (c-basic-offset . 4) + (c-comment-only-line-offset . 0) + (c-hanging-braces-alist . ((substatement-open after) + (brace-list-open after) + (brace-entry-open) + (defun-open after) + (class-open after) + (inline-open after) + (block-open after) + (block-close . c-snug-do-while) + (statement-case-open after) + (substatement after))) + (c-hanging-colons-alist . ((member-init-intro before) + (inher-intro) + (case-label after) + (label after) + (access-label after))) + (c-hanging-semi&comma-criteria . (c-semi&comma-no-newlines-before-nonblanks)) + (c-cleanup-list . (scope-operator + brace-else-brace + brace-elseif-brace + brace-catch-brace + empty-defun-braces + list-close-comma + defun-close-semi)) + (c-offsets-alist . ((inexpr-class . +) + (inexpr-statement . +) + (lambda-intro-cont . +) + (inlambda . c-lineup-inexpr-block) + (template-args-cont c-lineup-template-args +) + (incomposition . +) + (inmodule . +) + (innamespace . +) + (inextern-lang . +) + (composition-close . 0) + (module-close . 0) + (namespace-close . 0) + (extern-lang-close . 0) + (composition-open . 0) + (module-open . 0) + (namespace-open . 0) + (extern-lang-open . 0) + (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call +) + (objc-method-args-cont . c-lineup-ObjC-method-args) + (objc-method-intro . + [0]) + (friend . 0) + (cpp-define-intro c-lineup-cpp-define +) + (cpp-macro-cont . +) + (cpp-macro . + [0]) + (inclass . +) + (stream-op . c-lineup-streamop) + (arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist) + (arglist-cont c-lineup-gcc-asm-reg 0) + (arglist-intro . +) + (catch-clause . 0) + (else-clause . 0) + (do-while-closure . 0) + (label . 2) + (access-label . -) + (substatement-label . 2) + (substatement . +) + (statement-case-open . 0) + (statement-case-intro . +) + (statement-block-intro . +) + (statement-cont . +) + (statement . 0) + (brace-entry-open . 0) + (brace-list-entry . 0) + (brace-list-intro . +) + (brace-list-close . 0) + (brace-list-open . 0) + (block-close . 0) + (inher-cont . c-lineup-multi-inher) + (inher-intro . +) + (member-init-cont . c-lineup-multi-inher) + (member-init-intro . +) + (annotation-var-cont . +) + (annotation-top-cont . 0) + (topmost-intro-cont . c-lineup-topmost-intro-cont) + (topmost-intro . 0) + (knr-argdecl . 0) + (func-decl-cont . +) + (inline-close . 0) + (inline-open . +) + (class-close . 0) + (class-open . 0) + (defun-block-intro . +) + (defun-close . 0) + (defun-open . 0) + (string . c-lineup-dont-change) + (arglist-close . c-lineup-arglist) + (substatement-open . 0) + (case-label . 0) + (block-open . 0) + (c . 1) + (comment-intro . 0) + (knr-argdecl-intro . -))) + (fill-column . 80)))) diff --git a/include/libhqr.h b/include/libhqr.h index 526055421361130bcd83e7cacb7657a5b1d17d4b..8116981dd8c56d0e993cb77b7e3990ec92e2fdb0 100644 --- a/include/libhqr.h +++ b/include/libhqr.h @@ -64,14 +64,6 @@ typedef struct libhqr_tiledesc_s{ int p; } libhqr_tiledesc_t; - -typedef struct libhqr_file_tile_s{ - struct libhqr_file_tile_s *prev; - struct libhqr_file_tile_s *next; - int numero; -}libhqr_file_tile_t; - - struct libhqr_tree_s; typedef struct libhqr_tree_s libhqr_tree_t; @@ -162,43 +154,30 @@ struct libhqr_tree_s { }; int libhqr_systolic_init( libhqr_tree_t *qrtree, - libhqr_typefacto_e trans, libhqr_tiledesc_t *A, - int p, int q ); + libhqr_typefacto_e trans, libhqr_tiledesc_t *A, + int p, int q ); void libhqr_systolic_finalize( libhqr_tree_t *qrtree ); int libhqr_svd_init( libhqr_tree_t *qrtree, - libhqr_typefacto_e trans, libhqr_tiledesc_t *A, - int type_hlvl, int p, int nbcores_per_node, int ratio ); + libhqr_typefacto_e trans, libhqr_tiledesc_t *A, + int type_hlvl, int p, int nbcores_per_node, int ratio ); int libhqr_hqr_init( libhqr_tree_t *qrtree, - libhqr_typefacto_e trans, libhqr_tiledesc_t *A, - int type_llvl, int type_hlvl, - int a, int p, int domino, int tsrr ); + libhqr_typefacto_e trans, libhqr_tiledesc_t *A, + int type_llvl, int type_hlvl, + int a, int p, int domino, int tsrr ); void libhqr_hqr_finalize( libhqr_tree_t *qrtree ); - - - -/* - * functions for manipulate file - */ - -libhqr_file_tile_t *libhqr_file_tile_new (void); -void libhqr_file_tile_post (libhqr_file_tile_t ** file_tile,int numero); -int libhqr_file_tile_get (libhqr_file_tile_t ** file_tile); -void libhqr_file_tile_delete (libhqr_file_tile_t ** file_tile); - - /* * function for treewalk */ void libhqr_treewalk(libhqr_tree_t *qrtree,int k); - /* * Debugging functions */ + int libhqr_tree_check ( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree ); void libhqr_tree_print_dag ( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, char *filename ); void libhqr_tree_print_type ( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree ); diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..ebd2fd375c9195e3b75804a46f25b1027e51b598 --- /dev/null +++ b/include/queue.h @@ -0,0 +1,49 @@ +/** + * + * @file queue.h + * + * PaStiX symbol structure routines + * + * @copyright 2017 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + * Univ. Bordeaux. All rights reserved. + * + * @version 1.0.0 + * @author Raphael Boucherie + * @author Matthieu Faverge + * @date 2017-03-21 + * + **/ + +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#undef BEGIN_C_DECLS +#undef END_C_DECLS +#if defined(c_plusplus) || defined(__cplusplus) +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else +#define BEGIN_C_DECLS /* empty */ +#define END_C_DECLS /* empty */ +#endif + +BEGIN_C_DECLS + +typedef struct libhqr_queue_tile_s{ + struct libhqr_queue_tile_s *prev; + struct libhqr_queue_tile_s *next; + int numero; +} libhqr_queue_tile_t; + +libhqr_queue_tile_t *libhqr_queue_tile_new (void); +void libhqr_queue_tile_post (libhqr_queue_tile_t ** queue_tile,int numero); +int libhqr_queue_tile_get (libhqr_queue_tile_t ** queue_tile); +void libhqr_queue_tile_delete (libhqr_queue_tile_t ** queue_tile); +void libhqr_queue_tile_first (libhqr_queue_tile_t ** queue_tile); +void libhqr_queue_tile_prev (libhqr_queue_tile_t ** queue_tile); +void libhqr_queue_tile_last (libhqr_queue_tile_t ** queue_tile); +void libhqr_queue_tile_next (libhqr_queue_tile_t ** queue_tile); + +END_C_DECLS + +#endif /* _QUEUE_H_ */ diff --git a/src/libhqr_dbg.c b/src/libhqr_dbg.c index 023f1c0890e599b5423c9fadf47f0bf598fa4fcf..c87f34b29dfeaf4a9b1f207f7d0ff7667696ff3c 100644 --- a/src/libhqr_dbg.c +++ b/src/libhqr_dbg.c @@ -83,7 +83,7 @@ #define ENDCHECK( test, ret ) \ if ( !test ) \ - return ret; + return ret; int libhqr_tree_check( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree) { @@ -98,204 +98,204 @@ int libhqr_tree_check( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree) * Check Formula for NB geqrt */ { - /* libhqr_tree_print_type( A, qrtree ); */ - /* libhqr_tree_print_nbgeqrt( A, qrtree ); */ - check = 1; - for (k=0; k<minMN; k++) { - nb = 0; - for (m=k; m < A->mt; m++) { - if ( qrtree->gettype( qrtree, k, m ) > 0 ) - nb++; - } - - if ( nb != qrtree->getnbgeqrf( qrtree, k ) ) { - check = 0; - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Check number of geqrt:\n" - " For k=%d => return %d instead of %d", - a, p, A->mt, A->nt, k, qrtree->getnbgeqrf( qrtree, k ), nb ); - } - } - - ENDCHECK( check, 1 ); + /* libhqr_tree_print_type( A, qrtree ); */ + /* libhqr_tree_print_nbgeqrt( A, qrtree ); */ + check = 1; + for (k=0; k<minMN; k++) { + nb = 0; + for (m=k; m < A->mt; m++) { + if ( qrtree->gettype( qrtree, k, m ) > 0 ) + nb++; + } + + if ( nb != qrtree->getnbgeqrf( qrtree, k ) ) { + check = 0; + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Check number of geqrt:\n" + " For k=%d => return %d instead of %d", + a, p, A->mt, A->nt, k, qrtree->getnbgeqrf( qrtree, k ), nb ); + } + } + + ENDCHECK( check, 1 ); } /* * Check indices of geqrt */ { - int prevm = -1; - check = 1; - for (k=0; k<minMN; k++) { - /* libhqr_tree_print_geqrt_k( A, qrtree, k ); */ - nb = qrtree->getnbgeqrf( qrtree, k ); - prevm = -1; - for (i=0; i < nb; i++) { - - m = qrtree->getm( qrtree, k, i ); - - /* - * getm has to be the inverse of geti - */ - if ( i != qrtree->geti( qrtree, k, m) ) { - check = 0; - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Check indices of geqrt:\n" - " getm( k=%d, i=%d ) => m = %d && geti( k=%d, m=%d ) => i = %d\n", - a, p, A->mt, A->nt, - k, i, m, k, m, qrtree->geti( qrtree, k, m)); - } - /* tile before the diagonal are factorized and - * the m is a growing list (not true with round-robin inside TS) - */ - else if ( (a == 1) && (( m < k ) || ( m < prevm )) ) { - check = 0; - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Check indices of geqrt:\n" - " getm( k=%d, i=%d ) => m = %d", - a, p, A->mt, A->nt, k, i, m); - } + int prevm = -1; + check = 1; + for (k=0; k<minMN; k++) { + /* libhqr_tree_print_geqrt_k( A, qrtree, k ); */ + nb = qrtree->getnbgeqrf( qrtree, k ); + prevm = -1; + for (i=0; i < nb; i++) { + + m = qrtree->getm( qrtree, k, i ); + + /* + * getm has to be the inverse of geti + */ + if ( i != qrtree->geti( qrtree, k, m) ) { + check = 0; + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Check indices of geqrt:\n" + " getm( k=%d, i=%d ) => m = %d && geti( k=%d, m=%d ) => i = %d\n", + a, p, A->mt, A->nt, + k, i, m, k, m, qrtree->geti( qrtree, k, m)); + } + /* tile before the diagonal are factorized and + * the m is a growing list (not true with round-robin inside TS) + */ + else if ( (a == 1) && (( m < k ) || ( m < prevm )) ) { + check = 0; + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Check indices of geqrt:\n" + " getm( k=%d, i=%d ) => m = %d", + a, p, A->mt, A->nt, k, i, m); + } #if 0 - else if ( m != qrtree->getinon0( qrtree, k, i, A->mt ) ) { - check = 0; - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Check indices of geqrt:\n" - " getm( k=%d, i=%d ) => m = %d but should be %d", - a, p, A->mt, A->nt, k, i, m, qrtree->getinon0( qrtree, k, i, A->mt)); - } + else if ( m != qrtree->getinon0( qrtree, k, i, A->mt ) ) { + check = 0; + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Check indices of geqrt:\n" + " getm( k=%d, i=%d ) => m = %d but should be %d", + a, p, A->mt, A->nt, k, i, m, qrtree->getinon0( qrtree, k, i, A->mt)); + } #endif - prevm = m; - } - } - ENDCHECK( check, 2 ); + prevm = m; + } + } + ENDCHECK( check, 2 ); } /* * Check number of exit in next */ { - int s; - check = 1; - - for (k=0; k<minMN; k++) { - for(m=k; m<A->mt; m++) { - nb = 0; - for(s=A->mt; s>k; s--) { - if ( qrtree->nextpiv(qrtree, k, m, s) == A->mt ) - nb++; - } - if ( nb > 1 ) { - libhqr_tree_print_next_k( A, qrtree, k); - libhqr_tree_print_prev_k( A, qrtree, k); - - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Next of line %d for step %d contains more than one exit:\n", - a, p, A->mt, A->nt, - m, k); - check = 0; - return 3; - } - else if ( nb == 0 ) { - libhqr_tree_print_next_k( A, qrtree, k); - libhqr_tree_print_prev_k( A, qrtree, k); - - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Next of line %d for step %d needs one exit:\n", - a, p, A->mt, A->nt, - m, k); - check = 0; - return 3; - } - } - } - ENDCHECK( check, 3 ); + int s; + check = 1; + + for (k=0; k<minMN; k++) { + for(m=k; m<A->mt; m++) { + nb = 0; + for(s=A->mt; s>k; s--) { + if ( qrtree->nextpiv(qrtree, k, m, s) == A->mt ) + nb++; + } + if ( nb > 1 ) { + libhqr_tree_print_next_k( A, qrtree, k); + libhqr_tree_print_prev_k( A, qrtree, k); + + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Next of line %d for step %d contains more than one exit:\n", + a, p, A->mt, A->nt, + m, k); + check = 0; + return 3; + } + else if ( nb == 0 ) { + libhqr_tree_print_next_k( A, qrtree, k); + libhqr_tree_print_prev_k( A, qrtree, k); + + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Next of line %d for step %d needs one exit:\n", + a, p, A->mt, A->nt, + m, k); + check = 0; + return 3; + } + } + } + ENDCHECK( check, 3 ); } /* * Check number of exit in prev */ { - int s; - check = 1; - - for (k=0; k<minMN; k++) { - for(m=k; m<A->mt; m++) { - nb = 0; - for(s=k; s<A->mt; s++) { - if ( qrtree->prevpiv(qrtree, k, m, s) == A->mt ) - nb++; - } - if ( nb > 1 ) { - libhqr_tree_print_next_k( A, qrtree, k); - libhqr_tree_print_prev_k( A, qrtree, k); - - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Prev of line %d for step %d contains more than one exit:\n", - a, p, A->mt, A->nt, - m, k); - check = 0; - return 3; - } - else if ( nb == 0 ) { - libhqr_tree_print_next_k( A, qrtree, k); - libhqr_tree_print_prev_k( A, qrtree, k); - - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Prev of line %d for step %d needs one exit:\n", - a, p, A->mt, A->nt, - m, k); - check = 0; - return 3; - } - } - } - ENDCHECK( check, 3 ); + int s; + check = 1; + + for (k=0; k<minMN; k++) { + for(m=k; m<A->mt; m++) { + nb = 0; + for(s=k; s<A->mt; s++) { + if ( qrtree->prevpiv(qrtree, k, m, s) == A->mt ) + nb++; + } + if ( nb > 1 ) { + libhqr_tree_print_next_k( A, qrtree, k); + libhqr_tree_print_prev_k( A, qrtree, k); + + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Prev of line %d for step %d contains more than one exit:\n", + a, p, A->mt, A->nt, + m, k); + check = 0; + return 3; + } + else if ( nb == 0 ) { + libhqr_tree_print_next_k( A, qrtree, k); + libhqr_tree_print_prev_k( A, qrtree, k); + + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Prev of line %d for step %d needs one exit:\n", + a, p, A->mt, A->nt, + m, k); + check = 0; + return 3; + } + } + } + ENDCHECK( check, 3 ); } /* * Check next/prev */ { - int start, next, prev; - check = 1; - - for (k=0; k<minMN; k++) { - start = A->mt; - for(m=k; m<A->mt; m++) { - - do { - next = qrtree->nextpiv(qrtree, k, m, start); - if ( next == A->mt ) - prev = qrtree->prevpiv(qrtree, k, m, m); - else - prev = qrtree->prevpiv(qrtree, k, m, next); - - if ( start != prev ) { - libhqr_tree_print_next_k( A, qrtree, k); - libhqr_tree_print_prev_k( A, qrtree, k); - - printf(" ----------------------------------------------------\n" - " - a = %d, p = %d, M = %d, N = %d\n" - " Check next/prev:\n" - " next( m=%d, k=%d, start=%d ) => %d && prev( m=%d, k=%d, start=%d ) => %d\n ( %d != %d )", - a, p, A->mt, A->nt, - m, k, start, next, m, k, next, prev, start, prev); - check = 0; - return 3; - } - start = next; - } while ( start != A->mt ); - } - } - ENDCHECK( check, 3 ); + int start, next, prev; + check = 1; + + for (k=0; k<minMN; k++) { + start = A->mt; + for(m=k; m<A->mt; m++) { + + do { + next = qrtree->nextpiv(qrtree, k, m, start); + if ( next == A->mt ) + prev = qrtree->prevpiv(qrtree, k, m, m); + else + prev = qrtree->prevpiv(qrtree, k, m, next); + + if ( start != prev ) { + libhqr_tree_print_next_k( A, qrtree, k); + libhqr_tree_print_prev_k( A, qrtree, k); + + printf(" ----------------------------------------------------\n" + " - a = %d, p = %d, M = %d, N = %d\n" + " Check next/prev:\n" + " next( m=%d, k=%d, start=%d ) => %d && prev( m=%d, k=%d, start=%d ) => %d\n ( %d != %d )", + a, p, A->mt, A->nt, + m, k, start, next, m, k, next, prev, start, prev); + check = 0; + return 3; + } + start = next; + } while ( start != A->mt ); + } + } + ENDCHECK( check, 3 ); } return 0; @@ -311,29 +311,29 @@ void libhqr_tree_print_type( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree ) printf("\n------------ Localization = Type of pivot --------------\n"); for(m=0; m<A->mt; m++) { - printf("%3d | ", m); - for (k=0; k<libhqr_imin(minMN, m+1); k++) { - printf( "%3d ", qrtree->gettype( qrtree, k, m ) ); - } - for (k=libhqr_imin(minMN, m+1); k<minMN; k++) { - printf( " " ); - } - - printf(" "); - printf("%2d,%3d | ", rank, lmg); - for (k=0; k<libhqr_imin(minMN, lmg+1); k++) { - printf( "%3d ", qrtree->gettype( qrtree, k, lmg) ); - } - for (k=libhqr_imin(minMN, lmg+1); k<minMN; k++) { - printf( " " ); - } - lm++; lmg+=qrtree->p; - if ( lmg >= A->mt ) { - rank++; - lmg = rank; - lm = 0; - } - printf("\n"); + printf("%3d | ", m); + for (k=0; k<libhqr_imin(minMN, m+1); k++) { + printf( "%3d ", qrtree->gettype( qrtree, k, m ) ); + } + for (k=libhqr_imin(minMN, m+1); k<minMN; k++) { + printf( " " ); + } + + printf(" "); + printf("%2d,%3d | ", rank, lmg); + for (k=0; k<libhqr_imin(minMN, lmg+1); k++) { + printf( "%3d ", qrtree->gettype( qrtree, k, lmg) ); + } + for (k=libhqr_imin(minMN, lmg+1); k<minMN; k++) { + printf( " " ); + } + lm++; lmg+=qrtree->p; + if ( lmg >= A->mt ) { + rank++; + lmg = rank; + lm = 0; + } + printf("\n"); } } @@ -346,29 +346,29 @@ void libhqr_tree_print_pivot( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree ) int rank = 0; printf("\n------------ Current Pivot--------------\n"); for(m=0; m<A->mt; m++) { - printf("%3d | ", m); - for (k=0; k<libhqr_imin(minMN, m+1); k++) { - printf( "%3d ", qrtree->currpiv(qrtree, k, m) ); - } - for (k=libhqr_imin(minMN, m+1); k<minMN; k++) { - printf( " " ); - } - - printf(" "); - printf("%2d,%3d | ", rank, lmg); - for (k=0; k<libhqr_imin(minMN, lmg+1); k++) { - printf( "%3d ", qrtree->currpiv(qrtree, k, lmg) ); - } - for (k=libhqr_imin(minMN, lmg+1); k<minMN; k++) { - printf( " " ); - } - lm++; lmg+=qrtree->p; - if ( lmg >= A->mt ) { - rank++; - lmg = rank; - lm = 0; - } - printf("\n"); + printf("%3d | ", m); + for (k=0; k<libhqr_imin(minMN, m+1); k++) { + printf( "%3d ", qrtree->currpiv(qrtree, k, m) ); + } + for (k=libhqr_imin(minMN, m+1); k<minMN; k++) { + printf( " " ); + } + + printf(" "); + printf("%2d,%3d | ", rank, lmg); + for (k=0; k<libhqr_imin(minMN, lmg+1); k++) { + printf( "%3d ", qrtree->currpiv(qrtree, k, lmg) ); + } + for (k=libhqr_imin(minMN, lmg+1); k<minMN; k++) { + printf( " " ); + } + lm++; lmg+=qrtree->p; + if ( lmg >= A->mt ) { + rank++; + lmg = rank; + lm = 0; + } + printf("\n"); } } @@ -379,15 +379,15 @@ void libhqr_tree_print_next_k( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, int printf( " " ); for(s=A->mt; s>0; s--) - printf( "%3d ", s ); + printf( "%3d ", s ); printf( "\n" ); for(m=0; m<A->mt; m++) { - printf("%3d | ", m); - for(s=A->mt; s>0; s--) { - printf( "%3d ", qrtree->nextpiv(qrtree, k, m, s) ); - } - printf("\n"); + printf("%3d | ", m); + for(s=A->mt; s>0; s--) { + printf( "%3d ", qrtree->nextpiv(qrtree, k, m, s) ); + } + printf("\n"); } } @@ -398,15 +398,15 @@ void libhqr_tree_print_prev_k( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, int printf( " " ); for(s=A->mt; s>-1; s--) - printf( "%3d ", s ); + printf( "%3d ", s ); printf( "\n" ); for(m=0; m<A->mt; m++) { - printf("%3d | ", m); - for(s=A->mt; s>-1; s--) { - printf( "%3d ", qrtree->prevpiv(qrtree, k, m, s) ); - } - printf("\n"); + printf("%3d | ", m); + for(s=A->mt; s>-1; s--) { + printf( "%3d ", qrtree->prevpiv(qrtree, k, m, s) ); + } + printf("\n"); } } @@ -418,19 +418,19 @@ void libhqr_tree_print_perm( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, int *p printf("\n------------ Permutation --------------\n"); for (k=0; k<minMN; k++) { - printf( "%3d ", k ); + printf( "%3d ", k ); } printf( "\n" ); for (k=0; k<minMN; k++) { - printf( "----" ); + printf( "----" ); } printf( "\n" ); for (m=0; m < A->mt+1; m++) { - for (k=0; k<minMN; k++) { - printf( "%3d ", perm[ k*(A->mt+1) + m ] ); - } - printf( "\n" ); + for (k=0; k<minMN; k++) { + printf( "%3d ", perm[ k*(A->mt+1) + m ] ); + } + printf( "\n" ); } printf( "\n" ); } @@ -443,22 +443,22 @@ void libhqr_tree_print_nbgeqrt( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree ) printf("\n------------ Nb GEQRT per k --------------\n"); printf(" k : "); for (k=0; k<minMN; k++) { - printf( "%3d ", k ); + printf( "%3d ", k ); } printf( "\n" ); printf(" Compute: "); for (k=0; k<minMN; k++) { - nb = 0; - for (m=k; m < A->mt; m++) { - if ( qrtree->gettype(qrtree, k, m) > 0 ) - nb++; - } - printf( "%3d ", nb ); + nb = 0; + for (m=k; m < A->mt; m++) { + if ( qrtree->gettype(qrtree, k, m) > 0 ) + nb++; + } + printf( "%3d ", nb ); } printf( "\n" ); printf(" Formula: "); for (k=0; k<minMN; k++) { - printf( "%3d ", qrtree->getnbgeqrf( qrtree, k ) ); + printf( "%3d ", qrtree->getnbgeqrf( qrtree, k ) ); } printf( "\n" ); } @@ -473,11 +473,11 @@ void libhqr_tree_print_geqrt_k( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, int printf( " m:"); nb = qrtree->getnbgeqrf( qrtree, k ); for (i=0; i < nb; i++) { - m = qrtree->getm( qrtree, k, i ); - if ( i == qrtree->geti( qrtree, k, m) ) - printf( "%3d ", m ); - else - printf( "x%2d ", qrtree->geti( qrtree, k, m) ); + m = qrtree->getm( qrtree, k, i ); + if ( i == qrtree->geti( qrtree, k, m) ) + printf( "%3d ", m ); + else + printf( "x%2d ", qrtree->geti( qrtree, k, m) ); } printf( "\n" ); } @@ -537,64 +537,64 @@ void libhqr_tree_print_dag( libhqr_tiledesc_t *A, libhqr_tree_t *qrtree, char *f /* Print header */ fprintf(f, DAG_HEADER ); /*, A->mt+2, minMN+2 );*/ for(m=0; m < A->mt; m++) { - fprintf(f, DAG_LABELNODE, m, m, m); + fprintf(f, DAG_LABELNODE, m, m, m); } for(k=0; k<minMN; k++ ) { - int nb2reduce = A->mt - k - 1; - - for(m=k; m < A->mt; m++) { - fprintf(f, DAG_STARTNODE, m, A->mt, k, pos[m], m, color[ (m%qrtree->p) % DAG_NBCOLORS ]); - next[m] = qrtree->nextpiv( qrtree, k, m, A->mt); - } - - while( nb2reduce > 0 ) { - memset(done, 0, A->mt * sizeof(int) ); - for(m=A->mt-1; m > (k-1); m--) { - n = next[m]; - if ( next[n] != A->mt ) - continue; - if ( n != A->mt ) { - lpos = libhqr_imax( pos[m], pos[n] ); - lpos++; - pos[m] = lpos; - pos[n] = lpos; - - fprintf(f, DAG_NODE, m, n, k, pos[m], m, color[ (m%qrtree->p) % DAG_NBCOLORS ]); - - prev = qrtree->prevpiv( qrtree, k, m, n ); - fprintf(f, DAG_EDGE_PIV, - m, prev, k, - m, n, k, - color[ (m%qrtree->p) % DAG_NBCOLORS ]); - - prev = qrtree->prevpiv( qrtree, k, n, n ); - if ( qrtree->gettype(qrtree, k, n) == 0 ) - fprintf(f, DAG_EDGE_TS, - n, prev, k, - m, n, k, - color[ (m%qrtree->p) % DAG_NBCOLORS ]); - else - fprintf(f, DAG_EDGE_TT, - n, prev, k, - m, n, k, - color[ (m%qrtree->p) % DAG_NBCOLORS ]); - - next[m] = qrtree->nextpiv( qrtree, k, m, n); - done[m] = done[n] = 1; - nb2reduce--; - } - } - } + int nb2reduce = A->mt - k - 1; + + for(m=k; m < A->mt; m++) { + fprintf(f, DAG_STARTNODE, m, A->mt, k, pos[m], m, color[ (m%qrtree->p) % DAG_NBCOLORS ]); + next[m] = qrtree->nextpiv( qrtree, k, m, A->mt); + } + + while( nb2reduce > 0 ) { + memset(done, 0, A->mt * sizeof(int) ); + for(m=A->mt-1; m > (k-1); m--) { + n = next[m]; + if ( next[n] != A->mt ) + continue; + if ( n != A->mt ) { + lpos = libhqr_imax( pos[m], pos[n] ); + lpos++; + pos[m] = lpos; + pos[n] = lpos; + + fprintf(f, DAG_NODE, m, n, k, pos[m], m, color[ (m%qrtree->p) % DAG_NBCOLORS ]); + + prev = qrtree->prevpiv( qrtree, k, m, n ); + fprintf(f, DAG_EDGE_PIV, + m, prev, k, + m, n, k, + color[ (m%qrtree->p) % DAG_NBCOLORS ]); + + prev = qrtree->prevpiv( qrtree, k, n, n ); + if ( qrtree->gettype(qrtree, k, n) == 0 ) + fprintf(f, DAG_EDGE_TS, + n, prev, k, + m, n, k, + color[ (m%qrtree->p) % DAG_NBCOLORS ]); + else + fprintf(f, DAG_EDGE_TT, + n, prev, k, + m, n, k, + color[ (m%qrtree->p) % DAG_NBCOLORS ]); + + next[m] = qrtree->nextpiv( qrtree, k, m, n); + done[m] = done[n] = 1; + nb2reduce--; + } + } + } } length = 0; for(m=0; m < A->mt; m++) { - length = libhqr_imax(length, pos[m]); + length = libhqr_imax(length, pos[m]); } length++; for(k=0; k<length; k++) - fprintf(f, DAG_LENGTHNODE, k, k, k); + fprintf(f, DAG_LENGTHNODE, k, k, k); fprintf(f, DAG_FOOTER); printf("Tic Max = %d\n", length-1); diff --git a/src/libhqr_systolic.c b/src/libhqr_systolic.c index f76dbf80efa0036f71e668442d9835b087909aea..a60adfdba0044b25a9a1a51af654628a6cca0bed 100644 --- a/src/libhqr_systolic.c +++ b/src/libhqr_systolic.c @@ -63,11 +63,11 @@ static int systolic_gettype( const libhqr_tree_t *qrtree, int k, int m ) { /* Local eliminations with a TS kernel */ if ( m >= k + pq ) - return 0; + return 0; /* Element to be reduce with a single pivot */ else if ( m >= k+p ) - return 1; + return 1; /* Element to be reduced with sq_p pivot */ else return 3; @@ -88,16 +88,16 @@ static int systolic_currpiv(const libhqr_tree_t *qrtree, int k, int m) switch( systolic_gettype( qrtree, k, m ) ) { case 0: - return (m - k) % pq + k; - break; + return (m - k) % pq + k; + break; case 1: - return (m - k) % p + k; - break; + return (m - k) % p + k; + break; case 3: - return k; - break; + return k; + break; default: - return qrtree->mt; + return qrtree->mt; } }; @@ -136,59 +136,59 @@ static int systolic_nextpiv(const libhqr_tree_t *qrtree, int k, int pivot, int s lp = systolic_gettype( qrtree, k, pivot ); switch( ls ) - { - case -1: + { + case -1: - if ( lp == LIBHQR_KILLED_BY_TS ) { - myassert( start == mt ); - return mt; - } + if ( lp == LIBHQR_KILLED_BY_TS ) { + myassert( start == mt ); + return mt; + } - case LIBHQR_KILLED_BY_TS: + case LIBHQR_KILLED_BY_TS: - if ( start == mt ) - nextp = pivot + pq; - else - nextp = start + pq; + if ( start == mt ) + nextp = pivot + pq; + else + nextp = start + pq; - if ( nextp < mt ) - return nextp; + if ( nextp < mt ) + return nextp; - start = mt; + start = mt; - case LIBHQR_KILLED_BY_LOCALTREE: + case LIBHQR_KILLED_BY_LOCALTREE: - if (lp < LIBHQR_KILLED_BY_DISTTREE) - return mt; + if (lp < LIBHQR_KILLED_BY_DISTTREE) + return mt; - if ( start == mt ) - nextp = pivot + p; - else - nextp = start + p; + if ( start == mt ) + nextp = pivot + p; + else + nextp = start + p; - if ( (nextp >= k + p) && - (nextp < k + pq) && - (nextp < mt) ) - return nextp; + if ( (nextp >= k + p) && + (nextp < k + pq) && + (nextp < mt) ) + return nextp; - start = mt; + start = mt; - case LIBHQR_KILLED_BY_DISTTREE: + case LIBHQR_KILLED_BY_DISTTREE: - if (pivot > k) - return mt; + if (pivot > k) + return mt; - if ( start == mt ) - nextp = pivot + 1; - else - nextp = start + 1; + if ( start == mt ) + nextp = pivot + 1; + else + nextp = start + 1; - if ( nextp < k + p ) - return nextp; + if ( nextp < k + p ) + return nextp; - default: - return mt; - } + default: + return mt; + } } /** @@ -232,63 +232,63 @@ static int systolic_prevpiv(const libhqr_tree_t *qrtree, int k, int pivot, int s myassert( lp >= ls ); switch( ls ) - { - case LIBHQR_KILLED_BY_DISTTREE: - - if ( pivot == k ) { - if ( start == pivot ) { - nextp = start + p-1; - - while( pivot < nextp && nextp >= mt ) - nextp--; - } else { - nextp = start - 1; - } - - if ( pivot < nextp && - nextp < k + p ) - return nextp; - } - start = pivot; - - case LIBHQR_KILLED_BY_LOCALTREE: - - if ( lp > LIBHQR_KILLED_BY_LOCALTREE ) { - if ( start == pivot ) { - nextp = start + (q-1) * p; - - while( pivot < nextp && - nextp >= mt ) - nextp -= p; - } else { - nextp = start - p; - } - - if ( pivot < nextp && - nextp < k + pq ) - return nextp; - } - start = pivot; - - case LIBHQR_KILLED_BY_TS: - /* Search for predecessor in TS tree */ - if ( lp > LIBHQR_KILLED_BY_TS ) { - if ( start == pivot ) { - nextp = mt - (mt - rpivot - 1)%pq - 1; - - while( pivot < nextp && nextp >= mt ) - nextp -= pq; - } else { - nextp = start - pq; - } - assert(nextp < mt); - if ( pivot < nextp ) - return nextp; - } - - default: - return mt; - } + { + case LIBHQR_KILLED_BY_DISTTREE: + + if ( pivot == k ) { + if ( start == pivot ) { + nextp = start + p-1; + + while( pivot < nextp && nextp >= mt ) + nextp--; + } else { + nextp = start - 1; + } + + if ( pivot < nextp && + nextp < k + p ) + return nextp; + } + start = pivot; + + case LIBHQR_KILLED_BY_LOCALTREE: + + if ( lp > LIBHQR_KILLED_BY_LOCALTREE ) { + if ( start == pivot ) { + nextp = start + (q-1) * p; + + while( pivot < nextp && + nextp >= mt ) + nextp -= p; + } else { + nextp = start - p; + } + + if ( pivot < nextp && + nextp < k + pq ) + return nextp; + } + start = pivot; + + case LIBHQR_KILLED_BY_TS: + /* Search for predecessor in TS tree */ + if ( lp > LIBHQR_KILLED_BY_TS ) { + if ( start == pivot ) { + nextp = mt - (mt - rpivot - 1)%pq - 1; + + while( pivot < nextp && nextp >= mt ) + nextp -= pq; + } else { + nextp = start - pq; + } + assert(nextp < mt); + if ( pivot < nextp ) + return nextp; + } + + default: + return mt; + } }; /** @@ -349,29 +349,29 @@ static int systolic_prevpiv(const libhqr_tree_t *qrtree, int k, int pivot, int s ******************************************************************************/ int libhqr_systolic_init( libhqr_tree_t *qrtree, - libhqr_typefacto_e trans, libhqr_tiledesc_t *A, - int p, int q ) + libhqr_typefacto_e trans, libhqr_tiledesc_t *A, + int p, int q ) { if (qrtree == NULL) { - fprintf(stderr, "libhqr_systolic_init, illegal value of qrtree"); - return -1; + fprintf(stderr, "libhqr_systolic_init, illegal value of qrtree"); + return -1; } if ((trans != LIBHQR_QR) && - (trans != LIBHQR_LQ)) { - fprintf(stderr, "libhqr_systolic_init, illegal value of trans"); - return -2; + (trans != LIBHQR_LQ)) { + fprintf(stderr, "libhqr_systolic_init, illegal value of trans"); + return -2; } if (A == NULL) { - fprintf(stderr, "libhqr_systolic_init, illegal value of A"); - return -3; + fprintf(stderr, "libhqr_systolic_init, illegal value of A"); + return -3; } if ( p < 0 ) { - fprintf(stderr, "libhqr_systolic_init, illegal value of p"); - return -4; + fprintf(stderr, "libhqr_systolic_init, illegal value of p"); + return -4; } if ( q < -1 ) { - fprintf(stderr, "libhqr_systolic_init, illegal value of q"); - return -5; + fprintf(stderr, "libhqr_systolic_init, illegal value of q"); + return -5; } qrtree->getnbgeqrf = systolic_getnbgeqrf; @@ -415,6 +415,6 @@ void libhqr_systolic_finalize( libhqr_tree_t *qrtree ) { if ( qrtree->args != NULL) { - free( qrtree->args ); + free( qrtree->args ); } } diff --git a/src/treewalk.c b/src/treewalk.c index d38c366f9a1606b0654a8b7e24b435544c68c484..06c026bf04706315f186e63f7d6736dbf7f4c629 100644 --- a/src/treewalk.c +++ b/src/treewalk.c @@ -1,4 +1,22 @@ +/** + * + * @file treewalk.c + * + * PaStiX symbol structure routines + * + * @copyright 2017 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + * Univ. Bordeaux. All rights reserved. + * + * @version 1.0.0 + * @author Raphael Boucherie + * @author Matthieu Faverge + * @date 2017-03-21 + * + **/ + + #include "libhqr.h" +#include "queue.h" #include <assert.h> #include <stdlib.h> #include <string.h> @@ -16,167 +34,141 @@ /**************************************************** - * - * Generic functions for file - * + * Generic functions for queue ***************************************************/ - -static void libhqr_file_tile_first (libhqr_file_tile_t ** file_tile); -static void libhqr_file_tile_last (libhqr_file_tile_t ** file_tile); -static void libhqr_file_tile_prev (libhqr_file_tile_t ** file_tile); -static void libhqr_file_tile_next (libhqr_file_tile_t ** file_tile); - -libhqr_file_tile_t *libhqr_file_tile_new (void) +libhqr_queue_tile_t *libhqr_queue_tile_new (void) { return (NULL); } -static void libhqr_file_tile_first (libhqr_file_tile_t ** file_tile) +void libhqr_queue_tile_first (libhqr_queue_tile_t ** queue_tile) { - if (file_tile != NULL && *file_tile != NULL) + if (queue_tile != NULL && *queue_tile != NULL) { - while ((*file_tile)->prev != NULL) - libhqr_file_tile_prev (file_tile); + while ((*queue_tile)->prev != NULL) + libhqr_queue_tile_prev (queue_tile); } return; } -static void libhqr_file_tile_prev (libhqr_file_tile_t ** file_tile) +void libhqr_queue_tile_prev (libhqr_queue_tile_t ** queue_tile) { - if (file_tile != NULL && *file_tile != NULL) - *file_tile = (*file_tile)->prev; + if (queue_tile != NULL && *queue_tile != NULL) + *queue_tile = (*queue_tile)->prev; return; } -static void libhqr_file_tile_last (libhqr_file_tile_t ** file_tile) +void libhqr_queue_tile_last (libhqr_queue_tile_t ** queue_tile) { - if (file_tile != NULL && *file_tile != NULL) + if (queue_tile != NULL && *queue_tile != NULL) { - while ((*file_tile)->next != NULL) - libhqr_file_tile_next (file_tile); + while ((*queue_tile)->next != NULL) + libhqr_queue_tile_next (queue_tile); } return; } -static void libhqr_file_tile_next (libhqr_file_tile_t ** file_tile) +void libhqr_queue_tile_next (libhqr_queue_tile_t ** queue_tile) { - if (file_tile != NULL && *file_tile != NULL) - *file_tile = (*file_tile)->next; + if (queue_tile != NULL && *queue_tile != NULL) + *queue_tile = (*queue_tile)->next; return; } - -void libhqr_file_tile_post (libhqr_file_tile_t ** file_tile, int numero) + +void libhqr_queue_tile_post (libhqr_queue_tile_t ** queue_tile, int numero) { - if (file_tile != NULL) + if (queue_tile != NULL) { - libhqr_file_tile_t *p_l = NULL; - libhqr_file_tile_t *p_p = NULL; + libhqr_queue_tile_t *p_l = NULL; + libhqr_queue_tile_t *p_p = NULL; - libhqr_file_tile_first (file_tile); - p_l = *file_tile; + libhqr_queue_tile_first (queue_tile); + p_l = *queue_tile; p_p = malloc (sizeof (*p_p)); if (p_p != NULL) { - p_p->numero = numero; - p_p->next = p_l; - p_p->prev = NULL; - if (p_l != NULL) - p_l->prev = p_p; - *file_tile = p_p; + p_p->numero = numero; + p_p->next = p_l; + p_p->prev = NULL; + if (p_l != NULL) + p_l->prev = p_p; + *queue_tile = p_p; } else { - fprintf (stderr, "Memoire insuffisante\n"); - exit (EXIT_FAILURE); + fprintf (stderr, "Memoire insuffisante\n"); + exit (EXIT_FAILURE); } } return; } -int libhqr_file_tile_get (libhqr_file_tile_t ** file_tile) +int libhqr_queue_tile_get (libhqr_queue_tile_t ** queue_tile) { int ret; - if (file_tile != NULL && *file_tile != NULL) + if (queue_tile != NULL && *queue_tile != NULL) { - libhqr_file_tile_t *p_l = NULL; - libhqr_file_tile_t *p_p = NULL; + libhqr_queue_tile_t *p_l = NULL; + libhqr_queue_tile_t *p_p = NULL; - libhqr_file_tile_last (file_tile); - p_l = *file_tile; + libhqr_queue_tile_last (queue_tile); + p_l = *queue_tile; if (p_l != NULL) - p_p = p_l->prev; + p_p = p_l->prev; ret = p_l->numero; free (p_l); p_l = NULL; if (p_p != NULL) - p_p->next = NULL; - *file_tile = p_p; + p_p->next = NULL; + *queue_tile = p_p; } return (ret); } -void libhqr_file_tile_delete (libhqr_file_tile_t ** file_tile) +void libhqr_queue_tile_delete (libhqr_queue_tile_t ** queue_tile) { - if (file_tile != NULL && *file_tile != NULL) + if (queue_tile != NULL && *queue_tile != NULL) { - while (*file_tile != NULL) - libhqr_file_tile_get (file_tile); + while (*queue_tile != NULL) + libhqr_queue_tile_get (queue_tile); } return; } /**************************************************** - * - * fonctions pour parcourir arbre - * + * LIBHQR_TREEWALK ***************************************************/ void libhqr_treewalk(libhqr_tree_t *qrtree,int k){ - libhqr_file_tile_t **tt; - libhqr_file_tile_t **ts; - libhqr_file_tile_t *p_l = NULL; - libhqr_file_tile_t *p_p = NULL; + libhqr_queue_tile_t *tt; + libhqr_queue_tile_t *ts; + tt->next = libhqr_queue_tile_new(); + ts->next = libhqr_queue_tile_new(); + tt->prev = libhqr_queue_tile_new(); + ts->prev = libhqr_queue_tile_new(); int pivot = qrtree->p; int p = pivot; - while(p = qrtree->nextpiv(qrtree, k, pivot,p)){ - - while(p = qrtree->prevpiv(qrtree, k , pivot, p)){ - - if(qrtree->gettype(qrtree, k, p)) libhqr_file_tile_post(tt,p); - libhqr_file_tile_post(ts, p); - + int a,b; + while(p = qrtree->nextpiv(qrtree, k, pivot, p)){ + while(p = qrtree->prevpiv(qrtree, k, pivot, p)){ + if(qrtree->gettype(qrtree, k, p)) libhqr_queue_tile_post(&tt,p); //segfault + libhqr_queue_tile_post(&ts, p); } - libhqr_file_tile_last(ts); - p_l = *ts; - libhqr_file_tile_last(tt); - p_p = *tt; - int a = p_l->numero; - int b = p_p->numero; + libhqr_queue_tile_last(&ts); + a = ts->numero; + libhqr_queue_tile_last(&tt); + b = tt->numero; while(a != b){ - libhqr_file_tile_get(ts); - libhqr_file_tile_last(ts); - p_l = *ts; - a = p_l->numero; - printf("%d/n" , a); + libhqr_queue_tile_get(&ts); + libhqr_queue_tile_last(&ts); + a = ts->numero; } - libhqr_file_tile_get(tt); + libhqr_queue_tile_get(&tt); + libhqr_queue_tile_last(&tt); + b = tt->numero; } - libhqr_file_tile_delete(tt); - libhqr_file_tile_delete(ts); -} - - -/**************************************************** - * - * fonction utilisant l'algo de parcours d'arbre - * - ***************************************************/ - - -void libhqr_print_tree(libhqr_tree_t qrtree){ - - - + libhqr_queue_tile_delete(&tt); + libhqr_queue_tile_delete(&ts); } diff --git a/testings/testing_pivgen.c b/testings/testing_pivgen.c index 135f61a7d6e78f099fddd77085060678fb43a8d0..67f85dbfe9d1563d1efc680a0d7ec1f484fb5809 100644 --- a/testings/testing_pivgen.c +++ b/testings/testing_pivgen.c @@ -41,7 +41,7 @@ int main(int argc, char ** argv) todo += nbtreel * nbM * nbN * (2 * nbA - 1) * (1 + 2 * nbtreeh * nbP); /* systolic */ todo += nbM * nbN * nbA * nbP; - + /* * * Tests for HQR code diff --git a/testings/testing_treewalk.c b/testings/testing_treewalk.c index 933c64d5e1e741807899a60c462ea9f4b16c77eb..433474ceda2f3d4a8bf85e9e4b18f923dd2a4371 100644 --- a/testings/testing_treewalk.c +++ b/testings/testing_treewalk.c @@ -1,13 +1,22 @@ -/* - * Copyright (c) 2009-2011 The University of Tennessee and The University - * of Tennessee Research Foundation. All rights - * reserved. - * - * @precisions normal z -> s d c - * - */ +/** + * + * @file testing_treewalk.c + * + * PaStiX symbol structure routines + * + * @copyright 2017 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + * Univ. Bordeaux. All rights reserved. + * + * @version 1.0.0 + * @author Raphael Boucherie + * @author Matthieu Faverge + * @date 2017-03-21 + * + **/ + #include "libhqr.h" +#include "queue.h" #include <stdlib.h> #include <stdio.h> #include <string.h>