1 //------------------------------------------------------------------------------
2 // SLIP_LU/slip_internal: include file for internal use in SLIP_LU
3 //------------------------------------------------------------------------------
4 
5 // SLIP_LU: (c) 2019-2020, Chris Lourenco, Jinhao Chen, Erick Moreno-Centeno,
6 // Timothy A. Davis, Texas A&M University.  All Rights Reserved.  See
7 // SLIP_LU/License for the license.
8 
9 //------------------------------------------------------------------------------
10 
11 // This file is not intended to be #include'd in user applications.  Use
12 // SLIP_LU.h instead.
13 
14 #ifndef SLIP_LU_INTERNAL_H
15 #define SLIP_LU_INTERNAL_H
16 
17 #pragma GCC diagnostic ignored "-Wunused-parameter"
18 #pragma GCC diagnostic ignored "-Wunused-value"
19 
20 //------------------------------------------------------------------------------
21 //------------------------------------------------------------------------------
22 //-------------------------C Libraries------------------------------------------
23 //------------------------------------------------------------------------------
24 //------------------------------------------------------------------------------
25 
26 // Standard C libraries
27 #include <setjmp.h>
28 #include <math.h>
29 #include <stdarg.h>
30 #include <stdint.h>
31 #include <inttypes.h>
32 
33 // SuiteSparse headers
34 #include "SuiteSparse_config.h"
35 #include "colamd.h"
36 #include "amd.h"
37 
38 //------------------------------------------------------------------------------
39 // debugging
40 //------------------------------------------------------------------------------
41 
42 #ifdef SLIP_DEBUG
43 
44 #ifdef MATLAB_MEX_FILE
45 
46 #define ASSERT(x)                                                             \
47 {                                                                             \
48     if (!(x))                                                                 \
49     {                                                                         \
50         mexErrMsgTxt ("assertion failed: %s line %d\n", __FILE__, __LINE__) ; \
51     }                                                                         \
52 }
53 
54 #else
55 
56 #include <assert.h>
57 #define ASSERT(x) assert (x)
58 
59 #endif
60 
61 #else
62 
63 // debugging disabled
64 #define ASSERT(x)
65 
66 #endif
67 
68 //------------------------------------------------------------------------------
69 //-------------------------Common Macros----------------------------------------
70 //------------------------------------------------------------------------------
71 
72 #ifdef MATLAB_MEX_FILE
73 #include "mex.h"
74 #include "matrix.h"
75 #endif
76 
77 #define SLIP_MAX(a,b) (((a) > (b)) ? (a) : (b))
78 #define SLIP_MIN(a,b) (((a) < (b)) ? (a) : (b))
79 #define SLIP_FLIP(i) (-(i)-2)
80 #define SLIP_UNFLIP(i) (((i) < 0) ? SLIP_FLIP(i) : (i))
81 #define SLIP_MARKED(Ap,j) (Ap [j] < 0)
82 #define SLIP_MARK(Ap,j) { Ap [j] = SLIP_FLIP (Ap [j]) ; }
83 
84 // SLIP_CHECK(method) is a macro that calls a SLIP LU method and checks the
85 // status; if a failure occurs, it frees all allocated workspace and returns
86 // the error status to the caller.  To use SLIP_CHECK, the #include'ing file
87 // must declare a SLIP_info info, and must define SLIP_FREE_ALL as a macro that
88 // frees all workspace if an error occurs. The method can be a scalar as well,
89 // so that SLIP_CHECK(info) works.
90 
91 // the default is to free nothing
92 #ifndef SLIP_FREE_ALL
93 #define SLIP_FREE_ALL
94 #endif
95 
96 #define SLIP_CHECK(method)      \
97 {                               \
98     info = (method) ;           \
99     if (info != SLIP_OK)        \
100     {                           \
101         SLIP_FREE_ALL ;         \
102         return (info) ;         \
103     }                           \
104 }
105 
106 #include "SLIP_LU.h"
107 
108 //------------------------------------------------------------------------------
109 // printing control
110 //------------------------------------------------------------------------------
111 
112 // SLIP_LU uses SuiteSparse_config.printf_func instead of a mere call to printf
113 // (the default function is printf, or mexPrintf when in MATLAB).  If this
114 // function pointer is NULL, no printing is done.
115 
116 #define SLIP_PRINTF(...)                                    \
117 {                                                           \
118     if (SuiteSparse_config.printf_func != NULL)             \
119     {                                                       \
120         SuiteSparse_config.printf_func (__VA_ARGS__) ;      \
121     }                                                       \
122 }
123 
124 #define SLIP_PR1(...) { if (pr >= 1) SLIP_PRINTF (__VA_ARGS__) }
125 #define SLIP_PR2(...) { if (pr >= 2) SLIP_PRINTF (__VA_ARGS__) }
126 #define SLIP_PR3(...) { if (pr >= 3) SLIP_PRINTF (__VA_ARGS__) }
127 
128 //------------------------------------------------------------------------------
129 //------------------------------------------------------------------------------
130 //-------------------------functions for GMP wrapper----------------------------
131 //------------------------------------------------------------------------------
132 //------------------------------------------------------------------------------
133 // uncomment this to print memory debugging info
134 // #define SLIP_GMP_MEMORY_DEBUG
135 
136 #ifdef SLIP_GMP_MEMORY_DEBUG
137 void slip_gmp_dump ( void ) ;
138 #endif
139 
140 extern int64_t slip_gmp_ntrials ;
141 
142 #ifndef SLIP_GMP_LIST_INIT
143 // A size of 32 ensures that the list never needs to be increased in size.
144 // The test coverage suite in SLIP_LU/Tcov reduces this initial size to
145 // exercise the code, in SLIP_LU/Tcov/Makefile.
146 #define SLIP_GMP_LIST_INIT 32
147 #endif
148 
149 
150 bool slip_gmp_init (void) ;
151 
152 void slip_gmp_finalize (void) ;
153 
154 void *slip_gmp_allocate (size_t size) ;
155 
156 void slip_gmp_free (void *p, size_t size) ;
157 
158 void *slip_gmp_reallocate (void *p_old, size_t old_size, size_t new_size );
159 
160 void slip_gmp_failure (int status) ;
161 
162 
163 // Tolerance used in the pivoting schemes. This number can be anything in
164 // between 0 and 1. A value of 0 selects the diagonal element exclusively and a
165 // value of 1 selects the smallest or largest pivot exclusively only in a
166 // tolerance pivoting based method
167 #define SLIP_DEFAULT_TOL 1
168 
169 // Check parameter. If this = 1 then the solution to the system is checked
170 // for accuracy
171 #define SLIP_DEFAULT_CHECK false
172 
173 // Pivoting scheme used for SLIP LU.
174 //  SLIP_SMALLEST = 0,              Smallest pivot
175 //  SLIP_DIAGONAL = 1,              Diagonal pivoting
176 //  SLIP_FIRST_NONZERO = 2,         First nonzero per column chosen as pivot
177 //  SLIP_TOL_SMALLEST = 3,          Diagonal pivoting with tolerance for small
178 //  SLIP_TOL_LARGEST = 4,           Diagonal pivoting with tolerance for large
179 //  SLIP_LARGEST = 5                Largest pivot
180 #define SLIP_DEFAULT_PIVOT SLIP_TOL_SMALLEST
181 
182 // Column ordering used.
183 //  SLIP_NO_ORDERING = 0,           None: Not recommended for sparse matrices
184 //  SLIP_COLAMD = 1,                COLAMD: Default
185 //  SLIP_AMD = 2                    AMD
186 #define SLIP_DEFAULT_ORDER SLIP_COLAMD
187 
188 // Defines printing to be done
189 #define SLIP_DEFAULT_PRINT_LEVEL 0
190 
191 // MPFR precision used (quad is default)
192 #define SLIP_DEFAULT_PRECISION 128
193 
194 //------------------------------------------------------------------------------
195 // Type of MPFR rounding used.
196 //------------------------------------------------------------------------------
197 
198 // The MPFR library utilizes an internal rounding scheme. The options are
199 //  MPFR_RNDN: round to nearest (roundTiesToEven in IEEE 754-2008),
200 //  MPFR_RNDZ: round toward zero (roundTowardZero in IEEE 754-2008),
201 //  MPFR_RNDU: round toward plus infinity (roundTowardPositive in
202 //             IEEE 754-2008),
203 //  MPFR_RNDD: round toward minus infinity (roundTowardNegative in
204 //             IEEE 754-2008),
205 //  MPFR_RNDA: round away from zero.
206 //  MPFR_RNDF: faithful rounding. This is not stable
207 //
208 // SLIP LU utilizes MPFR_RNDN by default.
209 
210 #define SLIP_DEFAULT_MPFR_ROUND MPFR_RNDN
211 
212 //------------------------------------------------------------------------------
213 // Macros to utilize the default if option is NULL
214 //------------------------------------------------------------------------------
215 
216 #define SLIP_OPTION(option,parameter,default_value) \
217     ((option == NULL) ? (default_value) : (option->parameter))
218 
219 #define SLIP_OPTION_TOL(option) \
220     SLIP_OPTION (option, tol, SLIP_DEFAULT_TOL)
221 
222 #define SLIP_OPTION_CHECK(option) \
223     SLIP_OPTION (option, check, false)
224 
225 #define SLIP_OPTION_PIVOT(option) \
226     SLIP_OPTION (option, pivot, SLIP_DEFAULT_PIVOT)
227 
228 #define SLIP_OPTION_ORDER(option) \
229     SLIP_OPTION (option, order, SLIP_DEFAULT_ORDER)
230 
231 #define SLIP_OPTION_PREC(option) \
232     SLIP_OPTION (option, prec, SLIP_DEFAULT_PRECISION)
233 
234 #define SLIP_OPTION_PRINT_LEVEL(option) \
235     SLIP_OPTION (option, print_level, SLIP_DEFAULT_PRINT_LEVEL)
236 
237 #define SLIP_OPTION_ROUND(option) \
238     SLIP_OPTION (option, round, SLIP_DEFAULT_MPFR_ROUND)
239 
240 //------------------------------------------------------------------------------
241 // Field access macros for MPZ/MPQ/MPFR struct
242 //------------------------------------------------------------------------------
243 
244 // (similar definition in gmp-impl.h and mpfr-impl.h)
245 
246 #define SLIP_MPZ_SIZ(x)   ((x)->_mp_size)
247 #define SLIP_MPZ_PTR(x)   ((x)->_mp_d)
248 #define SLIP_MPZ_ALLOC(x) ((x)->_mp_alloc)
249 #define SLIP_MPQ_NUM(x)   mpq_numref(x)
250 #define SLIP_MPQ_DEN(x)   mpq_denref(x)
251 #define SLIP_MPFR_MANT(x) ((x)->_mpfr_d)
252 #define SLIP_MPFR_EXP(x)  ((x)->_mpfr_exp)
253 #define SLIP_MPFR_PREC(x) ((x)->_mpfr_prec)
254 #define SLIP_MPFR_SIGN(x) ((x)->_mpfr_sign)
255 
256 /*re-define but same result: */
257 #define SLIP_MPFR_REAL_PTR(x) (&((x)->_mpfr_d[-1]))
258 
259 /* Invalid exponent value (to track bugs...) */
260 #define SLIP_MPFR_EXP_INVALID \
261  ((mpfr_exp_t) 1 << (GMP_NUMB_BITS*sizeof(mpfr_exp_t)/sizeof(mp_limb_t)-2))
262 
263 /* Macros to set the pointer in mpz_t/mpq_t/mpfr_t variable to NULL. It is best
264  * practice to call these macros immediately after mpz_t/mpq_t/mpfr_t variable
265  * is declared, and before the mp*_init function is called. It would help to
266  * prevent error when SLIP_MP*_CLEAR is called before the variable is
267  * successfully initialized.
268  */
269 
270 #define SLIP_MPZ_SET_NULL(x)                \
271     SLIP_MPZ_PTR(x) = NULL;                 \
272     SLIP_MPZ_SIZ(x) = 0;                    \
273     SLIP_MPZ_ALLOC(x) = 0;
274 
275 #define SLIP_MPQ_SET_NULL(x)                     \
276     SLIP_MPZ_PTR(SLIP_MPQ_NUM(x)) = NULL;        \
277     SLIP_MPZ_SIZ(SLIP_MPQ_NUM(x)) = 0;           \
278     SLIP_MPZ_ALLOC(SLIP_MPQ_NUM(x)) = 0;         \
279     SLIP_MPZ_PTR(SLIP_MPQ_DEN(x)) = NULL;        \
280     SLIP_MPZ_SIZ(SLIP_MPQ_DEN(x)) = 0;           \
281     SLIP_MPZ_ALLOC(SLIP_MPQ_DEN(x)) = 0;
282 
283 #define SLIP_MPFR_SET_NULL(x)               \
284     SLIP_MPFR_MANT(x) = NULL;               \
285     SLIP_MPFR_PREC(x) = 0;                  \
286     SLIP_MPFR_SIGN(x) = 1;                  \
287     SLIP_MPFR_EXP(x) = SLIP_MPFR_EXP_INVALID;
288 
289 /* GMP does not give a mechanism to tell a user when an mpz, mpq, or mpfr
290  * item has been cleared; thus, if mp*_clear is called on an object that
291  * has already been cleared, gmp will crash. It is also not possible to
292  * set a mp*_t = NULL. Thus, this mechanism modifies the internal GMP
293  * size of entries to avoid crashing in the case that a mp*_t is cleared
294  * multiple times.
295  */
296 
297 #define SLIP_MPZ_CLEAR(x)                        \
298 {                                                \
299     if ((x) != NULL && SLIP_MPZ_PTR(x) != NULL)  \
300     {                                            \
301         mpz_clear(x);                            \
302         SLIP_MPZ_SET_NULL(x);                    \
303     }                                            \
304 }
305 
306 #define SLIP_MPQ_CLEAR(x)                   \
307 {                                           \
308     SLIP_MPZ_CLEAR(SLIP_MPQ_NUM(x));        \
309     SLIP_MPZ_CLEAR(SLIP_MPQ_DEN(x));        \
310 }
311 
312 #define SLIP_MPFR_CLEAR(x)                        \
313 {                                                 \
314     if ((x) != NULL && SLIP_MPFR_MANT(x) != NULL) \
315     {                                             \
316         mpfr_clear(x);                            \
317         SLIP_MPFR_SET_NULL(x);                    \
318     }                                             \
319 }
320 
321 
322 // ============================================================================
323 //                           Internal Functions
324 // ============================================================================
325 
326 // check if SLIP_initialize* has been called
327 bool slip_initialized ( void ) ;        // true if called, false if not
328 void slip_set_initialized (bool s) ;    // set global initialzed flag to s
329 
330 /* Purpose: This function takes as input a mpz_t SLIP_matrix and divides
331  * it by an mpz_t constant storing the solution in a mpq_t dense SLIP_matrix
332  * array. This is used internally to divide the solution vector by the
333  * determinant of the matrix.
334  */
335 SLIP_info slip_matrix_div // divides the x matrix by a scalar
336 (
337     SLIP_matrix **x2_handle,    // x2 = x/scalar
338     SLIP_matrix* x,             // input vector x
339     const mpz_t scalar,         // the scalar
340     const SLIP_options *option
341 ) ;
342 
343 /* Purpose: This function multiplies matrix x a scalar
344  */
345 SLIP_info slip_matrix_mul   // multiplies x by a scalar
346 (
347     SLIP_matrix *x,         // matrix to be multiplied
348     const mpz_t scalar      // scalar to multiply by
349 ) ;
350 
351 /* Purpose: This function performs sparse REF forward substitution. This is
352  * essentially the same as the sparse REF triangular solve applied to each
353  * column of the right hand side vectors. Like the normal one, this function
354  * expects that the matrix x is dense. As a result,the nonzero pattern is not
355  * computed and each nonzero in x is iterated across.  The system to solve is
356  * LDx = x.  On output, the mpz_t** x structure is modified.
357  */
358 SLIP_info slip_forward_sub
359 (
360     const SLIP_matrix *L,   // lower triangular matrix
361     SLIP_matrix *x,         // right hand side matrix
362     const SLIP_matrix *rhos // sequence of pivots used in factorization
363 );
364 
365 /* Purpose: This function performs sparse REF backward substitution. In essense
366  * it solves the sysem Ux = x. Note that prior to this, we expect x to be
367  * multiplied by the determinant of A.  The input argument bx is modified on
368  * output.
369  */
370 SLIP_info slip_back_sub  // performs sparse REF backward substitution
371 (
372     const SLIP_matrix *U,   // input upper triangular matrix
373     SLIP_matrix *bx        // right hand side matrix of size n*numRHS
374 )  ;
375 
376 
377 //------------------------------------------------------------------------------
378 // mpfr_vector: a 1D mpfr_t array
379 //------------------------------------------------------------------------------
380 
381 // Creates a simple 1D array, where A[i] is an entry of type mpfr_t.
382 
383 /* Purpose: This function creates a MPFR array of desired precision*/
384 mpfr_t* slip_create_mpfr_array
385 (
386     int64_t n,     // size of the array
387     const SLIP_options* option
388 );
389 
390 // Creates a simple 1D array, where A[i] is an entry of type mpq_t.
391 
392 /* Purpose: This function creates an mpq array of size n.
393  * This function must be called for all mpq arrays created.
394  */
395 mpq_t* slip_create_mpq_array
396 (
397     int64_t n              // size of the array
398 );
399 
400 
401 //------------------------------------------------------------------------------
402 // mpz_vector: a 1D mpz_t array
403 //------------------------------------------------------------------------------
404 
405 // Creates a simple 1D array, where A[i] is an entry of type mpz_t.
406 
407 /* Purpose: This function creates an mpz array of size n and allocates
408  * default size.
409  */
410 mpz_t* slip_create_mpz_array
411 (
412     int64_t n              // Size of x
413 );
414 
415 /* SLIP_check_solution: checks the solution of the linear system.  Performs a
416  * quick rational arithmetic check of A*x=b.
417  */
418 SLIP_info slip_check_solution
419 (
420     const SLIP_matrix *A,          // input matrix
421     const SLIP_matrix *x,          // solution vector
422     const SLIP_matrix *b,          // right hand side
423     const SLIP_options* option           // Command options
424 );
425 
426 /* Purpose: p [0..n] = cumulative sum of c [0..n-1], and then copy p [0..n-1]
427  * into c.  This function is lightly modified from CSparse.
428  */
429 SLIP_info slip_cumsum
430 (
431     int64_t *p,          // vector to store the sum of c
432     int64_t *c,          // vector which is summed
433     int64_t n           // size of c
434 );
435 
436 /* Purpose: This function performs a depth first search of the graph of the
437  * matrix starting at node j. The output of this function is the set of nonzero
438  * indices in the xi vector.
439  */
440 void slip_dfs // performs a dfs of the graph of the matrix starting at node j
441 (
442     int64_t *top,          // beginning of stack
443     int64_t j,             // What node to start DFS at
444     SLIP_matrix* L,        // matrix which represents the Graph of L
445     int64_t* xi,           // the nonzero pattern
446     int64_t* pstack,       // workspace vector
447     const int64_t* pinv   // row permutation
448 );
449 
450 /* Purpose: This function converts a double array of size n to an appropriate
451  * mpz array of size n. To do this, the number is multiplied by 10^17 then, the
452  * GCD is found. This function allows the use of matrices in double precision
453  * to work with SLIP LU.
454  */
455 SLIP_info slip_expand_double_array
456 (
457     mpz_t *x_out,   // integral final array
458     double* x,      // double array that needs to be made integral
459     mpq_t scale,    // the scaling factor used (x_out = scale * x)
460     int64_t n,      // size of x
461     const SLIP_options* option
462 );
463 
464 /* Purpose: This function converts a mpfr array of size n and precision prec to
465  * an appropriate mpz array of size n. To do this, the number is multiplied by
466  * the appropriate power of 10 then the gcd is found. This function allows mpfr
467  * arrays to be used within SLIP LU.
468  */
469 SLIP_info slip_expand_mpfr_array
470 (
471     mpz_t *x_out,   // integral final array
472     mpfr_t* x,      // mpfr array to be expanded
473     mpq_t scale,    // scaling factor used (x_out = scale*x)
474     int64_t n,      // size of x
475     const SLIP_options *option // command options containing the prec for mpfr
476 );
477 
478 /* Purpose: This function converts a mpq array of size n into an appropriate mpz
479  * array of size n. To do this, the lcm of the denominators is found as a
480  * scaling factor. This function allows mpq arrays to be used in SLIP LU
481  */
482 SLIP_info slip_expand_mpq_array
483 (
484     mpz_t *x_out, // integral final array
485     mpq_t* x,     // mpq array that needs to be converted
486     mpq_t scale,  // scaling factor. x_out = scale*x
487     int64_t n,     // size of x
488     const SLIP_options* option // Command options
489 );
490 
491 /* Purpose: This function converts a mpq matrix of size m*n into an appropriate
492  * mpz matrix of size m*n. To do this, the lcm of the denominators is found as a
493  * scaling factor. This function allows mpq matrix to be used in SLIP LU.
494  * on output, x2 is modified.
495  */
496 SLIP_info slip_expand_mpq_mat
497 (
498     mpz_t **x_out,// integral final mat
499     mpq_t **x,    // mpq mat that needs to be converted
500     mpq_t scale,  // scaling factor. x_out = scale*x
501     int64_t m,    // number of rows of x
502     int64_t n     // number of columns of x
503 );
504 
505 /* This function performs the pivoting for the SLIP LU factorization.
506  * The optional Order is:
507  *     0: Smallest pivot
508  *     1: Natural/Diagonal pivoting
509  *     2: Choose first nonzero (not recommended, for comparison only)
510  *     3: Diagonal with tolerance and smallest pivot (default)
511  *     4: Diagonal with tolerance and largest pivoting
512  *     5: Largest pivot (not recommended, for comparison only)
513  *
514  * On output, the pivs, pinv, and row_perm arrays and rhos matrix are all modified.
515  */
516 SLIP_info slip_get_pivot
517 (
518     int64_t *pivot,      // found index of pivot entry
519     SLIP_matrix* x,      // kth column of L and U
520     int64_t* pivs,       // vector indicating which rows have been pivotal
521     int64_t n,           // dimension of the problem
522     int64_t top,         // nonzero pattern is located in xi[top..n-1]
523     int64_t* xi,         // nonzero pattern of x
524     int64_t col,         // current column of A (real kth column i.e., q[k])
525     int64_t k,           // iteration of the algorithm
526     SLIP_matrix* rhos,   // vector of pivots
527     int64_t* pinv,       // row permutation
528     int64_t* row_perm,   // opposite of pinv. if pinv[i] = j then row_perm[j] = i
529     const SLIP_options *option // command option
530 );
531 
532 /* Purpose: This function selects the pivot element as the largest in the
533  * column. This is activated if the user sets option->pivot = SLIP_LARGEST.
534  * NOTE: This pivoting scheme is NOT recommended for SLIP LU.  On output, the
535  * index of the largest pivot is returned.
536  */
537 SLIP_info slip_get_largest_pivot
538 (
539     int64_t *pivot,         // the index of largest pivot
540     SLIP_matrix* x,         // kth column of L and U
541     int64_t* pivs,          // vector which indicates whether each row has been pivotal
542     int64_t n,              // dimension of problem
543     int64_t top,            // nonzero pattern is located in xi[top..n-1]
544     int64_t* xi             // nonzero pattern of x
545 );
546 
547 /* This function obtains the first eligible nonzero pivot.  This is enabled if
548  * the user sets option->pivot = SLIP_FIRST_NONZERO.  NOTE: This pivoting
549  * scheme is not recommended.  On output, the kth pivot is returned.
550  */
551 SLIP_info slip_get_nonzero_pivot // find the first eligible nonzero pivot
552 (
553     int64_t *pivot,      // the index of first eligible nonzero pivot
554     SLIP_matrix* x,      // kth column of L and U
555     int64_t* pivs,       // vector indicating which rows are pivotal
556     int64_t n,           // size of x
557     int64_t top,         // nonzero pattern is located in xi[top..n-1]
558     int64_t* xi          // nonzero pattern of x
559 );
560 
561 /* Purpose: This function selects the pivot element as the smallest in the
562  * column. This is activated by default or if the user sets option->pivot =
563  * SLIP_SMALLEST.  NOTE: This is the recommended pivoting scheme for SLIP LU.
564  * On output, the index of kth pivot is returned.
565  */
566 SLIP_info slip_get_smallest_pivot
567 (
568     int64_t *pivot,         // index of smallest pivot
569     SLIP_matrix *x,         // kth column of L and U
570     int64_t* pivs,          // vector indicating whether each row has been pivotal
571     int64_t n,              // dimension of problem
572     int64_t top,            // nonzeros are stored in xi[top..n-1]
573     int64_t* xi             // nonzero pattern of x
574 );
575 
576 /* Purpose: This function prints the basic info about SLIP_LU library */
577 void slip_lu_info(void);
578 
579 /* Purpose: This function permutes b for forward substitution.
580  * That is, b = P'*b.
581  */
582 SLIP_info slip_permute_b
583 (
584     SLIP_matrix **b_handle,     // permuted RHS vector
585     const SLIP_matrix *b2,      // unpermuted RHS vector (not modified)
586     const int64_t *pinv,        // inverse row permutation
587     const SLIP_options* option
588 );
589 
590 /* Purpose: SLIP_permute_x permutes x to get it back in its original form.
591  * That is x = Q*x.
592  */
593 SLIP_info slip_permute_x
594 (
595     SLIP_matrix **x_handle,    // permuted Solution vector
596     SLIP_matrix *x2,           // unpermuted Solution vector (not modified)
597     SLIP_LU_analysis *S,  // symbolic analysis with the column ordering Q
598     const SLIP_options* option  // Command options
599                           // has been checked in the only caller SLIP_LU_solve
600 ) ;
601 
602 /* Purpose: This function collapses a SLIP matrix. Essentially it shrinks the
603  * size of x and i. so that they only take up the number of elements in the
604  * matrix. For example if A->nzmax = 1000 but nnz(A) = 500, r and x are of size
605  * 1000, so this function shrinks them to size 500.
606  */
607 SLIP_info slip_sparse_collapse
608 (
609     SLIP_matrix* A // matrix to be shrunk
610 );
611 
612 /* Purpose: This function expands a SLIP LU matrix by doubling its size. It
613  * merely expands x and i and does not initialize/allocate the values.
614  */
615 SLIP_info slip_sparse_realloc
616 (
617     SLIP_matrix* A // the matrix to be expanded
618 );
619 
620 /* Purpose: This function computes the reach of column k of A on the graph of L
621  * mathematically that is: xi = Reach(A(:,k))_G_L.
622  */
623 void slip_reach    // compute the reach of column k of A on the graph of L
624 (
625     int64_t *top,
626     SLIP_matrix* L,         // matrix representing graph of L
627     const SLIP_matrix* A,   // input matrix
628     int64_t k,              // column of A of interest
629     int64_t* xi,            // nonzero pattern
630     const int64_t* pinv     // row permutation
631 )  ;
632 
633 /* Purpose: This function performs the sparse REF triangular solve; that is,
634  * (LD) x = A(:,k). The algorithm is described in the paper; however in essence
635  * it computes the nonzero pattern xi, then performs a sequence of IPGE
636  * operations on the nonzeros to obtain their final value. All operations are
637  * gauranteed to be integral. There are various enhancements in this code used
638  * to reduce the overall cost of the operations and minimize operations as much
639  * as possible.
640  */
641 SLIP_info slip_ref_triangular_solve // performs the sparse REF triangular solve
642 (
643     int64_t *top_output,      // Output the beginning of nonzero pattern
644     SLIP_matrix* L,           // partial L matrix
645     const SLIP_matrix* A,     // input matrix
646     int64_t k,                // iteration of algorithm
647     int64_t* xi,              // nonzero pattern vector
648     const int64_t* q,         // column permutation
649     SLIP_matrix* rhos,        // sequence of pivots
650     const int64_t* pinv,      // inverse row permutation
651     const int64_t* row_perm,  // row permutation
652     int64_t* h,               // history vector
653     SLIP_matrix* x            // solution of system ==> kth column of L and U
654 );
655 
656 // typecast a double value to int64, accounting for Infs and Nans
slip_cast_double_to_int64(double x)657 static inline int64_t slip_cast_double_to_int64 (double x)
658 {
659     if (isnan (x))
660     {
661         return (0) ;
662     }
663     else if (x >= (double) INT64_MAX)
664     {
665         return (INT64_MAX) ;
666     }
667     else if (x <= (double) INT64_MIN)
668     {
669         return (INT64_MIN) ;
670     }
671     else
672     {
673         return ((int64_t) (x)) ;
674     }
675 }
676 
677 SLIP_info slip_cast_array
678 (
679     void *Y,                // output array, of size n
680     SLIP_type ytype,        // type of Y
681     void *X,                // input array, of size n
682     SLIP_type xtype,        // type of X
683     int64_t n,              // size of Y and X
684     mpq_t y_scale,          // scale factor applied if y is mpz_t
685     mpq_t x_scale,          // scale factor applied if x is mpz_t
686     const SLIP_options *option
687 ) ;
688 
689 SLIP_info slip_cast_matrix
690 (
691     SLIP_matrix **Y_handle,     // nz-by-1 dense matrix to create
692     SLIP_type Y_type,           // type of Y
693     SLIP_matrix *A,             // matrix with nz entries
694     const SLIP_options *option
695 ) ;
696 
697 // (void *) pointer to the values of A.  A must be non-NULL with a valid type
698 #define SLIP_X(A)                                                           \
699     ((A->type == SLIP_MPZ  ) ? (void *) A->x.mpz   :                        \
700     ((A->type == SLIP_MPQ  ) ? (void *) A->x.mpq   :                        \
701     ((A->type == SLIP_MPFR ) ? (void *) A->x.mpfr  :                        \
702     ((A->type == SLIP_INT64) ? (void *) A->x.int64 : (void *) A->x.fp64))))
703 
704 
705 // return an error if A->kind (csc, triplet, dense) is wrong
706 #define SLIP_REQUIRE_KIND(A,required_kind) \
707     if (A == NULL || A->kind != required_kind) return (SLIP_INCORRECT_INPUT) ;
708 
709 #define ASSERT_KIND(A,required_kind) \
710     ASSERT (A != NULL && A->kind == required_kind)
711 
712 // return an error if A->type (mpz, mpq, mpfr, int64, or double) is wrong
713 #define SLIP_REQUIRE_TYPE(A,required_type) \
714     if (A == NULL || A->type != required_type) return (SLIP_INCORRECT_INPUT) ;
715 
716 #define ASSERT_TYPE(A,required_type) \
717     ASSERT (A != NULL && A->type == required_type)
718 
719 // return an error if A->kind or A->type is wrong
720 #define SLIP_REQUIRE(A,required_kind,required_type)     \
721     SLIP_REQUIRE_KIND (A,required_kind) ;               \
722     SLIP_REQUIRE_TYPE (A,required_type) ;
723 
724 #define ASSERT_MATRIX(A,required_kind,required_type)    \
725     ASSERT_KIND (A,required_kind) ;                     \
726     ASSERT_TYPE (A,required_type) ;
727 
728 #endif
729 
730