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