1 //------------------------------------------------------------------------------
2 // SLIP_LU/Demo/SLIPLU.c: example main program for 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 #include "demos.h"
12
13 /* This program will exactly solve the sparse linear system Ax = b by
14 * performing the SLIP LU factorization. This is intended to be a demonstration
15 * of the "advanced interface" of SLIP LU. Refer to README.txt for
16 * information on how to properly use this code
17 */
18
19 // usage:
20 // SLIPLU Followed by the listed args:
21 //
22 // help. e.g., SLIPLU help, which indicates SLIPLU to print to guideline
23 // for using this function.
24 //
25 // f (or file) Filename. e.g., SLIPLU f MATRIX_NAME RHS_NAME, which indicates
26 // SLIPLU will read matrix from MATRIX_NAME and right hand side from RHS_NAME.
27 // The matrix must be stored in Matrix Market format. Refer to
28 // http://math.nist.gov/MatrixMarket/formats.html for information on
29 // Matrix Market format.
30 // The right hand side vector must be stored as a dense vector.
31 //
32 // p (or piv) Pivot_param. e.g., SLIPLU p 0, which inidcates SLIPLU will use
33 // smallest pivot for pivot scheme. Other available options are listed
34 // as follows:
35 // 0: Smallest pivot: Default and recommended
36 // 1: Diagonal pivoting
37 // 2: First nonzero per column chosen as pivot
38 // 3: Diagonal pivoting with tolerance for smallest pivot
39 // 4: Diagonal pivoting with tolerance for largest pivot
40 // 5: Largest pivot
41 //
42 // q (or col) Column_order_param. e.g., SLIPLU q 1, which indicates SLIPLU
43 // will use COLAMD for column ordering. Other available options are:
44 // 0: None: Not recommended for sparse matrices
45 // 1: COLAMD: Default
46 // 2: AMD
47 //
48 // t (or tol) tolerance_param. e.g., SLIPLU t 1e-10, which indicates SLIPLU
49 // will use 1e-10 as the tolerance for pivot scheme 3 and 4 mentioned above.
50 // Therefore, it is only necessary if pivot scheme 3 or 4 is used.
51 //
52 // o (or out). e.g., SLIPLU o 1, which indicates SLIPLU will output the
53 // errors and warnings during the process. Other available options are:
54 // 0: print nothing
55 // 1: just errors and warnings: Default
56 // 2: terse, with basic stats from COLAMD/AMD and SLIP and solution
57 //
58 //
59 // If none of the above args is given, they are set to the following default:
60 //
61 // mat_name = "../ExampleMats/10teams_mat.txt"
62 // rhs_name = "../ExampleMats/10teams_v.txt"
63 // p = 0, i.e., using smallest pivot
64 // q = 1, i.e., using COLAMD
65 // t = 0.1, not being using since p != 3 or 4
66
67
68 #define FREE_WORKSPACE \
69 SLIP_matrix_free(&A, option); \
70 SLIP_matrix_free(&L, option); \
71 SLIP_matrix_free(&U, option); \
72 SLIP_matrix_free(&x, option); \
73 SLIP_matrix_free(&b, option); \
74 SLIP_matrix_free(&rhos, option); \
75 SLIP_FREE(pinv); \
76 SLIP_LU_analysis_free(&S, option); \
77 SLIP_FREE(option); \
78 SLIP_finalize( ) ;
79
main(int argc,char * argv[])80 int main (int argc, char* argv[])
81 {
82
83 //--------------------------------------------------------------------------
84 // Prior to using SLIP LU, its environment must be initialized. This is done
85 // by calling the SLIP_initialize() function.
86 //--------------------------------------------------------------------------
87
88 SLIP_initialize();
89
90 //--------------------------------------------------------------------------
91 // We first initialize the default parameters. These parameters are modified
92 // either via command line arguments or when reading in data. The important
93 // initializations are in the block below.
94 //
95 // First, we initialize 6 SLIP_matrices. Note that these matrices must
96 // simply be declared, they will be created and allocated within their
97 // respective functions. These matrices are:
98 //
99 // A: User input matrix. Must be SLIP_CSC and SLIP_MPZ for routines
100 //
101 // L: Lower triangular matrix. Will be output as SLIP_CSC and SLIP_MPZ
102 //
103 // U: Upper triangular matrix. Will be output as SLIP_CSC and SLIP_MPZ
104 //
105 // x: Solution to the linear system. Will be output as SLIP_DENSE and SLIP_MPQ
106 //
107 // b: Set of right hand side vectors. Must be SLIP_DENSE and SLIP_MPZ
108 //
109 // Additionally, two other data structures are declared here:
110 //
111 // pinv: Inverse row permutation used for LDU factorization and permutation
112 //
113 // S: Symbolic analysis struct.
114 //
115 // Lastly, the following parameter is created:
116 //
117 // option: Command options for the factorization. In general, this can be
118 // set to default values and is almost always the last input argument
119 // for SLIP LU functions (except SLIP_malloc and such)
120 //--------------------------------------------------------------------------
121 SLIP_matrix *A = NULL;
122 SLIP_matrix *L = NULL;
123 SLIP_matrix *U = NULL;
124 SLIP_matrix *x = NULL;
125 SLIP_matrix *b = NULL;
126 SLIP_matrix *rhos = NULL;
127 int64_t* pinv = NULL;
128 SLIP_LU_analysis* S = NULL;
129
130 // Initialize option, command options for the factorization
131 SLIP_options *option = SLIP_create_default_options();
132
133 // Extra parameters used to obtain A, b, etc
134 SLIP_info ok ;
135 char *mat_name, *rhs_name;
136 SLIP_type rat;
137 mat_name = "../ExampleMats/10teams_mat.txt";// Set demo matrix and RHS name
138 rhs_name = "../ExampleMats/10teams_v.txt";
139
140 if (!option)
141 {
142 fprintf (stderr, "Error! OUT of MEMORY!\n");
143 SLIP_finalize();
144 return 0;
145 }
146
147 //--------------------------------------------------------------------------
148 // After initializing memory, we process the command line for this function.
149 // Such a step is optional, a user can also manually set these parameters.
150 // For example, if one wished to use the AMD ordering, they can just set
151 // option->order = SLIP_AMD.
152 //--------------------------------------------------------------------------
153
154 bool help ;
155 OK(SLIP_process_command_line(argc, argv, option,
156 &mat_name, &rhs_name, &rat, &help));
157 if (help) return (0) ;
158
159 //--------------------------------------------------------------------------
160 // In this demo file, we now read in the A and b matrices from external
161 // files. Refer to the example.c file or the user guide for other
162 // methods of creating the input matrix. In general, the user can create
163 // his/her matrix (say in double form) and then create a copy of it with
164 // SLIP_matrix_copy
165 //--------------------------------------------------------------------------
166
167 // Read in A
168 FILE* mat_file = fopen(mat_name,"r");
169 if( mat_file == NULL )
170 {
171 perror("Error while opening the file");
172 FREE_WORKSPACE;
173 return 0;
174 }
175 OK(SLIP_tripread(&A, mat_file, option));
176 fclose(mat_file);
177
178 // Read in right hand side
179 FILE* rhs_file = fopen(rhs_name,"r");
180 if( rhs_file == NULL )
181 {
182 perror("Error while opening the file");
183 FREE_WORKSPACE;
184 return 0;
185 }
186 OK(SLIP_read_dense(&b, rhs_file, option));
187 fclose(rhs_file);
188
189 // Check if the size of A matches b
190 if (A->n != b->m)
191 {
192 fprintf (stderr, "Error! Size of A and b do not match!\n");
193 FREE_WORKSPACE;
194 return 0;
195 }
196
197 //--------------------------------------------------------------------------
198 // We now perform symbolic analysis by getting the column preordering of
199 // the matrix A. This is done via the SLIP_LU_analyze function. The output
200 // of this function is a column permutation Q where we factor the matrix AQ
201 // and an estimate of the number of nonzeros in L and U.
202 //
203 // Note that in the simple interface demostrated in the example*.c files,
204 // all of the following code is condensed into the single SLIP_backslash
205 // function.
206 //--------------------------------------------------------------------------
207
208 clock_t start_col = clock();
209
210 // Column ordering using either AMD, COLAMD or nothing
211 OK(SLIP_LU_analyze(&S, A, option));
212 if (option->print_level > 0)
213 {
214 SLIP_print_options(option);
215 }
216
217 clock_t end_col = clock();
218
219 //--------------------------------------------------------------------------
220 // Now we perform the SLIP LU factorization to obtain matrices L and U and a
221 // row permutation P such that PAQ = LDU. Note that the D matrix is never
222 // explicitly constructed or used.
223 //--------------------------------------------------------------------------
224
225 clock_t start_factor = clock();
226
227 OK(SLIP_LU_factorize(&L, &U, &rhos, &pinv, A, S, option));
228
229 clock_t end_factor = clock();
230
231 //--------------------------------------------------------------------------
232 // We now solve the system Ax=b using the L and U factors computed above.
233 //--------------------------------------------------------------------------
234
235 clock_t start_solve = clock();
236
237 // SLIP LU has an optional check step which can verify that the solution
238 // vector x satisfies Ax=b in perfect precision intended for debugging.
239 //
240 // Note that this is entirely optional and not necessary. The solution
241 // returned is guaranteed to be exact. It appears here just as a
242 // verification that SLIP LU is computing its expected result. This test
243 // can fail only if it runs out of memory, or if there is a bug in the
244 // code. Also, note that this function can be quite time consuming; thus
245 // it is not recommended to be used in general.
246 //
247 // To enable said check, the following bool is set to true
248 //
249 option->check = true;
250
251 // Solve LDU x = b
252 OK(SLIP_LU_solve(&x, b,
253 (const SLIP_matrix *) A,
254 (const SLIP_matrix *) L,
255 (const SLIP_matrix *) U,
256 (const SLIP_matrix *) rhos,
257 S,
258 (const int64_t *) pinv,
259 option));
260
261 clock_t end_solve = clock();
262
263 // Done, x now contains the exact solution of the linear system Ax=b in
264 // dense rational form. There is an optional final step here where the user
265 // can cast their solution to a different data type or matrix format.
266 // Below, we have a block of code which illustrates how one would do this.
267
268 // Example of how to transform output. Uncomment if desired
269 //
270 // SLIP_kind my_kind = SLIP_DENSE; // SLIP_CSC, SLIP_TRIPLET or SLIP_DENSE
271 // SLIP_type my_type = SLIP_FP64; // SLIP_MPQ, SLIP_MPFR, or SLIP_FP64
272 //
273 // SLIP_matrix* my_x = NULL; // New output
274 // Create copy which is stored as my_kind and my_type:
275 // SLIP_matrix_copy( &my_x, my_kind, my_type, x, option);
276
277 // Timing stats
278 double t_sym = (double) (end_col-start_col)/CLOCKS_PER_SEC;
279 double t_factor = (double) (end_factor - start_factor) / CLOCKS_PER_SEC;
280 double t_solve = (double) (end_solve - start_solve) / CLOCKS_PER_SEC;
281
282 printf("\nNumber of L+U nonzeros: \t\t%"PRId64,
283 (L->p[L->n]) + (U->p[U->n]) - (L->m));
284 printf("\nSymbolic analysis time: \t\t%lf", t_sym);
285 printf("\nSLIP LU Factorization time: \t\t%lf", t_factor);
286 printf("\nFB Substitution time: \t\t\t%lf\n\n", t_solve);
287
288 //--------------------------------------------------------------------------
289 // Free Memory
290 //--------------------------------------------------------------------------
291
292 FREE_WORKSPACE;
293 printf ("\n%s: all tests passed\n\n", __FILE__) ;
294 return 0;
295 }
296
297