sparse_cholesky_smp

 


   more...


   more...

Computes the Cholesky factorization of a sparse real symmetric positive definite matrix A by an OpenMP parallelized supernodal algorithm and solves the sparse real positive definite system of linear equations Ax = b.

Synopsis

#include <imsl.h>

float *imsl_f_sparse_cholesky_smp (int n, int nz, Imsl_f_sparse_elem a[], float b[], , 0)

void  imsl_free_snodal_symbolic_factor (Imsl_snodal_symbolic_factor  *sym_factor)

void imsl_f_free_numeric_factor (Imsl_f_numeric_factor *num_factor)

The type double functions are imsl_d_sparse_cholesky_smp and imsl_d_free_numeric_factor.

Required Arguments

int n (Input)
The order of the input matrix.

int nz (Input)
Number of nonzeros in the lower triangle of the matrix.

Imsl_f_sparse_elem a[] (Input)
An array of length nz containing the location and value of each nonzero entry in the lower triangle of the matrix.

float b[] (Input)
An array of length n containing the right-hand side.

Return Value

A pointer to the solution x of the sparse symmetric positive definite linear system Ax = b. To release this space, use imsl_free. If no solution was computed, then NULL is returned.

Synopsis with Optional Arguments

#include <imsl.h>

float *imsl_f_sparse_cholesky_smp (int n, int nz, Imsl_f_sparse_elem a[], float b[],

IMSL_CSC_FORMAT, int col_ptr[], int row_ind[], float values[],

IMSL_PREORDERING, int preorder,

IMSL_RETURN_SYMBOLIC_FACTOR, Imsl_snodal_symbolic_factor *sym_factor,

IMSL_SUPPLY_SYMBOLIC_FACTOR, Imsl_snodal_symbolic_factor *sym_factor,

IMSL_SYMBOLIC_FACTOR_ONLY,

IMSL_RETURN_NUMERIC_FACTOR, Imsl_f_numeric_factor *num_factor,

IMSL_SUPPLY_NUMERIC_FACTOR, Imsl_f_numeric_factor *num_factor,

IMSL_NUMERIC_FACTOR_ONLY,

IMSL_SOLVE_ONLY,

IMSL_SMALLEST_DIAGONAL_ELEMENT, float *smallest_element,

IMSL_LARGEST_DIAGONAL_ELEMENT, float *largest_element,

IMSL_NUM_NONZEROS_IN_FACTOR, int *num_nonzeros,

IMSL_RETURN_USER, float x[],

0)

Optional Arguments

IMSL_CSC_FORMAT, int col_ptr[], int row_ind[], float values[] (Input)
Accept the coefficient matrix in compressed sparse column (CSC) format, as described in the Compressed Sparse Column (CSC) Format section of the “Introduction” chapter of this manual.

IMSL_PREORDERING, int preorder (Input)
The variant of the Minimum Degree Ordering (MDO) algorithm used in the preordering of matrix A:

preorder

Method

0

George and Liu’s Quotient Minimum Degree algorithm.

1

A variant of George and Liu’s Quotient Minimum Degree algorithm using a preprocessing phase and external degrees.

Default: preorder = 0.

IMSL_RETURN_SYMBOLIC_FACTOR, Imsl_snodal_symbolic_factor *sym_factor (Output)
A pointer to a structure of type Imsl_snodal_symbolic_factor containing, on return, the supernodal symbolic factorization of the input matrix. A detailed description of the Imsl_snodal_symbolic_factor structure is given in the following table:

Table 1 – Structure Imsl_snodal_symbolic_factor

Parameter

Data Type

Description

nzsub

int **

A pointer to an array containing the compressed row subscripts of the non-zero off-diagonal elements of the Cholesky factor.

xnzsub

int **

A pointer to an array of length n+1 containing indices for *nzsub. The row subscripts for the non-zeros in column j of the Cholesky factor are stored consecutively beginning with (*nzsub)[(*xnzsub)[j]].

maxsub

int

The number of elements in array *nzsub that are used as subscripts. Note that the size of *nzsub can be larger than maxsub.

xlnz

int **

A pointer to an array of length n+1 containing the starting and stopping indices to use to extract the non-zero off-diagonal elements from array *alnz (For a description of alnz, see the description section of optional argument IMSL_RETURN_NUMERIC_FACTOR). For column j of the factor matrix, the starting and stopping indices of *alnz are stored in (*xlnz) [j] and (*xlnz) [j+1] respectively.

maxlnz

int

The number of non-zero off-diagonal elements in the Cholesky factor.

perm

int **

A pointer to an array of length n containing the permutation vector.

invp

int **

A pointer to an array of length n containing the inverse permutation vector.

multifrontal_space

int

This variable is not used in the current implementation.

nsuper

int

The number of supernodes in the Cholesky factor.

snode

int **

A pointer to an array of length n. Element (*snode)[j] contains the number of the fundamental supernode to which column j belongs.

snode_ptr

int **

A pointer to an array of length nsuper+1 containing the start column of each supernode.

nleaves

int

The number of leaves in the postordered elimination tree of the symmetrically permuted input matrix A.

etree_leaves

int **

A pointer to an array of length nleaves+1 containing the leaves of the elimination tree.

To free the memory allocated within this structure, use function imsl_free_snodal_symbolic_factor.

IMSL_SUPPLY_SYMBOLIC_FACTOR, Imsl_snodal_symbolic_factor *sym_factor (Input)
A pointer to a structure of type Imsl_snodal_symbolic_factor. This structure contains the symbolic factorization of the input matrix computed by imsl_f_sparse_cholesky_smp with the IMSL_RETURN_SYMBOLIC_FACTOR option. The structure is described in the IMSL_RETURN_SYMBOLIC_FACTOR optional argument description.
To free the memory allocated within this structure, use function imsl_free_snodal_symbolic_factor.

IMSL_SYMBOLIC_FACTOR_ONLY, (Input)
Compute the symbolic factorization of the input matrix and return. The argument b is ignored.

IMSL_RETURN_NUMERIC_FACTOR, Imsl_f_numeric_factor *num_factor (Output)
A pointer to a structure of type Imsl_f_numeric_factor containing, on return, the numeric factorization of the input matrix. A detailed description of the Imsl_f_numeric_factor structure is given in the IMSL_RETURN_NUMERIC_FACTOR optional argument description of function imsl_f_lin_sol_posdef_coordinate. To free the memory allocated within this structure, use function imsl_f_free_numeric_factor.

IMSL_SUPPLY_NUMERIC_FACTOR, Imsl_f_numeric_factor *num_factor (Input)
A pointer to a structure of type Imsl_f_numeric_factor. This structure contains the numeric factorization of the input matrix computed by imsl_f_sparse_cholesky_smp with the IMSL_RETURN_NUMERIC_FACTOR option. The structure is described in the IMSL_RETURN_NUMERIC_FACTOR optional argument description of function imsl_f_lin_sol_posdef_coordinate.
To free the memory allocated within this structure, use function imsl_f_free_numeric_factor.

IMSL_NUMERIC_FACTOR_ONLY, (Input)
Compute the numeric factorization of the input matrix and return. The argument b is ignored.

IMSL_SOLVE_ONLY, (Input)
Solve Ax = b given the numeric or symbolic factorization of A. This option requires the use of either IMSL_SUPPLY_NUMERIC_FACTOR or IMSL_SUPPLY_SYMBOLIC_FACTOR.

IMSL_SMALLEST_DIAGONAL_ELEMENT, float *smallest_element (Output)
A pointer to a scalar containing the smallest diagonal element that occurred during the numeric factorization. This option is valid only if the numeric factorization is computed during this call to imsl_f_sparse_cholesky_smp.

IMSL_LARGEST_DIAGONAL_ELEMENT, float *largest_element (Output)
A pointer to a scalar containing the largest diagonal element that occurred during the numeric factorization. This option is valid only if the numeric factorization is computed during this call to imsl_f_sparse_cholesky_smp.

IMSL_NUM_NONZEROS_IN_FACTOR, int *num_nonzeros (Output)
A pointer to a scalar containing the total number of nonzeros in the factor.

IMSL_RETURN_USER, float x[] (Output)
A user-allocated array of length n containing the solution x.

Description

The function imsl_f_sparse_cholesky_smp solves a system of linear algebraic equations having a sparse symmetric positive definite coefficient matrix A. In this function’s default usage, a symbolic factorization of a permutation of the coefficient matrix is computed first. Then a numerical factorization exploiting OpenMP parallelism is performed. The solution of the linear system is then found using the numeric factor.

The symbolic factorization step of the computation consists of determining a minimum degree ordering and then setting up a sparse supernodal data structure for the Cholesky factor, L. This step only requires the “pattern” of the sparse coefficient matrix, i.e., the locations of the nonzeros elements but not any of the elements themselves. Thus, the val field in the Imsl_f_sparse_elem structure is ignored. If an application generates different sparse symmetric positive definite coefficient matrices that all have the same sparsity pattern, then by using IMSL_RETURN_SYMBOLIC_FACTOR and IMSL_SUPPLY_SYMBOLIC_FACTOR, the symbolic factorization needs only be computed once.

Given the sparse data structure for the Cholesky factor L, as supplied by the symbolic factor, the numeric factorization produces the entries in L so that

PAPT = LLT

Here P is the permutation matrix determined by the minimum degree ordering.

The numerical factorization is an implementation of a parallel supernodal algorithm that combines a left-looking and a right-looking column computation scheme. This algorithm is described in detail in Rauber et al. (1999).

If an application requires that several linear systems be solved where the coefficient matrix is the same but the right-hand sides change, the options IMSL_RETURN_NUMERIC_FACTOR and IMSL_SUPPLY_NUMERIC_FACTOR can be used to precompute the Cholesky factor. Then the IMSL_SOLVE_ONLY option can be used to efficiently solve all subsequent systems.

Given the numeric factorization, the solution x is obtained by the following calculations:

Ly1 = Pb

LTy2 = y1

x = PTy2

The permutation information, P, is carried in the numeric factor structure Imsl_f_numeric_factor.

Examples

Example 1

Consider the 5 × 5 coefficient matrix A,

 

The number of nonzeros in the lower triangle of A is nz = 10. We construct the solution xT = (5, 4, 3, 2, 1) to the system Ax = b by setting b := Ax = (55, 83, 103, 97, 82)T. The solution is computed and printed.

 

#include <imsl.h>

 

int main()

{

Imsl_f_sparse_elem a[] =

{0, 0, 10.0,

1, 1, 20.0,

2, 0, 1.0,

2, 2, 30.0,

3, 2, 4.0,

3, 3, 40.0,

4, 0, 2.0,

4, 1, 3.0,

4, 3, 5.0,

4, 4, 50.0};

 

float b[] = {55.0, 83.0, 103.0, 97.0, 82.0};

int n = 5, nz = 10;

float *x = NULL;

 

x = imsl_f_sparse_cholesky_smp (n, nz, a, b, 0);

 

imsl_f_write_matrix ("solution", 1, n, x, 0);

imsl_free (x);

}

Output

 

solution

1 2 3 4 5

5 4 3 2 1

Example 2

This example shows how a symbolic factor can be re-used. At first, the system Ax = b with A = E (2500, 50) is solved and the symbolic factorization of A is returned. Then, the system Cy = d with C = A+2*I, I the identity matrix, is solved using the symbolic factorization just computed. This is possible because A and C have the same nonzero structure and therefore also the same symbolic factorization. The solution errors are printed.

 

#include <imsl.h>

#include <stdlib.h>

#include <stdio.h>

 

int main()

{

Imsl_f_sparse_elem *a = NULL, *c = NULL;

Imsl_snodal_symbolic_factor symbolic_factor;

float *b = NULL, *d = NULL, *x = NULL, *y = NULL;

float *mod_vector = NULL;

int n, ic, nz, i, index;

float error_1, error_2;

 

ic = 50;

n = ic * ic;

mod_vector = (float*) malloc (n * sizeof(float));

 

/* Build coefficient matrix A */

a = (Imsl_f_sparse_elem *) imsl_f_generate_test_coordinate (n, ic,

&nz,

IMSL_SYMMETRIC_STORAGE,

0);

 

/* Build coefficient matrix C */

c = (Imsl_f_sparse_elem*) malloc (nz * sizeof(Imsl_f_sparse_elem));

for (i = 0; i < nz; i++) c[i] = a[i];

for (i = 0; i < n; i++)

c[i].val = 6.0;

 

/* Form right hand side b */

for (i = 0; i < n; i++)

mod_vector[i] = (float) (i % 5);

 

b = (float *) imsl_f_mat_mul_rect_coordinate ("A*x",

IMSL_A_MATRIX, n, n, nz, a,

IMSL_X_VECTOR, n, mod_vector,

IMSL_SYMMETRIC_STORAGE,

0);

 

/* Form right hand side d */

d = (float *) imsl_f_mat_mul_rect_coordinate ("A*x",

IMSL_A_MATRIX, n, n, nz, c,

IMSL_X_VECTOR, n, mod_vector,

IMSL_SYMMETRIC_STORAGE,

0);

 

/* Solve Ax = b and return the symbolic factorization */

x = imsl_f_sparse_cholesky_smp (n, nz, a, b,

IMSL_RETURN_SYMBOLIC_FACTOR, &symbolic_factor,

0);

 

/* Compute solution error |x - mod_vector| */

error_1 = imsl_f_vector_norm (n, x,

IMSL_SECOND_VECTOR, mod_vector,

IMSL_INF_NORM, &index,

0);

 

/* Solve Cy = d given the symbolic factorization */

y = imsl_f_sparse_cholesky_smp (n, nz, c, d,

IMSL_SUPPLY_SYMBOLIC_FACTOR, &symbolic_factor,

0);

 

/* Compute solution error |y - mod_vector| */

error_2 = imsl_f_vector_norm (n, y,

IMSL_SECOND_VECTOR, mod_vector,

IMSL_INF_NORM, &index,

0);

 

printf ("Solution error |x - mod_vector| = %e\n", error_1);

printf ("Solution error |y - mod_vector| = %e\n", error_2);

 

/* Free allocated memory */

if (b) imsl_free(b);

if (d) imsl_free(d);

if (x) imsl_free(x);

if (y) imsl_free(y);

if (mod_vector) free(mod_vector);

if (a) imsl_free(a);

if (c) free(c);

imsl_free_snodal_symbolic_factor (&symbolic_factor);

}

Output

 

Solution error |x - mod_vector| = 4.529953e-005

Solution error |y - mod_vector| = 2.861023e-006

Example 3

In this example, set A = E (2500, 50). First solve the system Ax = b1 and return the numeric factorization resulting from that call. Then solve the system Ax = b2 using the numeric factorization just computed. The ratio of execution times is printed. Be aware that timing results are highly machine dependent.

 

#include <imsl.h>

#include <stdio.h>

#include <omp.h>

 

int main()

{

int n, ic, nz;

float *b_1 = NULL, *b_2 = NULL, *x_1 = NULL, *x_2 = NULL;

double time_1, time_2;

Imsl_f_sparse_elem *a = NULL;

Imsl_f_numeric_factor numeric_factor;

 

ic = 50;

n = ic * ic;

 

/* Generate two right hand sides */

imsl_random_seed_set (1234567);

b_1 = imsl_f_random_uniform (n, 0);

b_2 = imsl_f_random_uniform (n, 0);

 

/* Build coefficient matrix a */

a = imsl_f_generate_test_coordinate (n, ic, &nz,

IMSL_SYMMETRIC_STORAGE,

0);

 

/* Now solve Ax_1 = b_1 and return the numeric

factorization */

 

time_1 = omp_get_wtime();

 

x_1 = imsl_f_sparse_cholesky_smp (n, nz, a, b_1,

IMSL_RETURN_NUMERIC_FACTOR, &numeric_factor,

0);

 

time_1 = omp_get_wtime() - time_1;

 

/* Now solve Ax_2 = b_2 given the numeric

factorization */

time_2 = omp_get_wtime();

 

x_2 = imsl_f_sparse_cholesky_smp (n, nz, a, b_2,

IMSL_SUPPLY_NUMERIC_FACTOR, &numeric_factor,

IMSL_SOLVE_ONLY,

0);

 

time_2 = omp_get_wtime() - time_2;

printf("time_2/time_1 = %lf\n", time_2/time_1);

 

/* Free allocated memory */

if (x_1) imsl_free(x_1);

if (x_2) imsl_free(x_2);

if (b_1) imsl_free(b_1);

if (b_2) imsl_free(b_2);

if (a) imsl_free(a);

imsl_f_free_numeric_factor (&numeric_factor);

}

 

Output

 

time_2/time_1 = 0.029411

Fatal Errors

IMSL_BAD_SQUARE_ROOT

A zero or negative square root has occurred during the factorization. The coefficient matrix is not positive definite.