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