LADEL main
Sparse LDL factorization package with rank 1 and rowadd/rowdel updates
ladel_row_mod.c
Go to the documentation of this file.
1#include "ladel.h"
2#include "ladel_types.h"
3#include "ladel_global.h"
4#include "ladel_constants.h"
5#include "ladel_pattern.h"
6#include "ladel_rank1_mod.h"
7#include "ladel_row_mod.h"
8#include "ladel_permutation.h"
9#include "ladel_debug_print.h"
10#include <math.h>
11
13{
14 if (!LD || !sym || !W || !work) return FAIL;
15
16 ladel_int start, index_in_pattern, ncol = sym->ncol, row, index, index2, Wnz, status;
17 ladel_sparse_matrix* L = LD->L;
18 ladel_double *Dinv = LD->Dinv;
19 ladel_int *etree = sym->etree;
20 ladel_double temp, d22 = diag;
22
23 ladel_set *l31_pattern = work->set_preallocated1;
24 l31_pattern->size_set = 0;
25 ladel_set *set_L31 = work->set_unallocated_values2;
26 ladel_set *difference = work->set_preallocated2;
27 ladel_int *offset = work->array_int_ncol1;
28 ladel_int *insertions = work->array_int_ncol2;
29
30 if (W->nz == NULL) Wnz = W->p[col_in_W+1] - W->p[col_in_W];
31 else Wnz = W->nz[col_in_W];
32
33 if (LD->pinv != NULL)
34 {
35 ladel_int_vector_copy(W->i + W->p[col_in_W], Wnz, work->array_int_ncol3);
36 ladel_double_vector_copy(W->x + W->p[col_in_W], Wnz, work->array_double_ncol1);
37 ladel_permute_sparse_vector(W, col_in_W, LD->pinv, work);
38 row_in_L = LD->pinv[row_in_L];
39 }
40
41 /* 1. Solve lower triangular system L11*D11*l12 = W12 */
42
43
44 for (index = W->p[col_in_W]; index < W->p[col_in_W] + Wnz; index++)
45 {
46 row = W->i[index];
47 l12[row] = W->x[index];
48 if (row > row_in_L)
49 {
50 l31_pattern->set[l31_pattern->size_set] = row;
51 l31_pattern->size_set++;
52 }
53 }
54
55 start = ladel_etree_dfs(W, sym, col_in_W, row_in_L);
56 for (index_in_pattern = start; index_in_pattern < ncol; index_in_pattern++)
57 {
58 row = sym->pattern[index_in_pattern];
59 temp = l12[row];
60 /* 2. d22 = c22 - l12^T D11*l12 */
61 d22 -= temp*temp*Dinv[row];
62
63 l12[row] *= Dinv[row];
64 /* Gaussian elimination */
65 for (index = L->p[row]; index < (L->p[row] + L->nz[row]) && L->i[index] < row_in_L; index++)
66 {
67 l12[L->i[index]] -= L->x[index]*temp;
68 }
69 /* 3. l32 = (c32 - L31*D11*l12)/d22 */
70 ladel_set_set(set_L31, L->i + index, (L->p[row] + L->nz[row])-index, ncol);
71 ladel_set_union(l31_pattern, set_L31, difference, offset, insertions, row_in_L);
72 for (index2 = (L->p[row] + L->nz[row] - 1); index2 >= index; index2--)
73 {
74 l12[L->i[index2]] -= L->x[index2]*temp;
75
76 /* Shift the columns down by one to make room for l12*/
77 L->i[index2+1] = L->i[index2];
78 L->x[index2+1] = L->x[index2];
79 }
80 /* Insert l12[row] */
81 L->i[index] = row_in_L;
82 L->x[index] = l12[row];
83 l12[row] = 0;
84 L->nz[row]++;
85 if (etree[row] == NONE || etree[row] > row_in_L) etree[row] = row_in_L;
86 }
87
88 /* Insert l31 */
89 d22 = Dinv[row_in_L] = 1/d22;
90 L->nz[row_in_L] = l31_pattern->size_set;
91 LADEL_FOR(index, L, row_in_L)
92 {
93 L->i[index] = row = l31_pattern->set[index-L->p[row_in_L]];
94 L->x[index] = d22*l12[row];
95 l12[row] = 0;
96 }
97 if (l31_pattern->size_set > 0)
98 {
99 etree[row_in_L] = L->i[L->p[row_in_L]];
100 }
101
102 /* Reset the diagonal element from W (this was not used and so not reset yet).*/
103 l12[row_in_L] = 0;
104
105 /* 4. w = l32*sqrt(abs(d22)) */
106 /* 5. Update or downdate L33*D33*L33^T = L33*D33*L33^T - sign(d22)*w*w^T */
107 status = ladel_rank1_update(LD, sym, L, row_in_L, 1/sqrt(LADEL_ABS(d22)), d22 < 0, work);
108
109
110 /* Restore W if permuted*/
111 if (LD->pinv != NULL)
112 {
113 ladel_int_vector_copy(work->array_int_ncol3, Wnz, W->i + W->p[col_in_W]);
114 ladel_double_vector_copy(work->array_double_ncol1, Wnz, W->x + W->p[col_in_W]);
115 }
116
117 return status;
118}
119
121{
122 if (!LD || !sym || !work) return FAIL;
123 ladel_int status, index_of_row_in_L, index, found, col,
124 top, bottom, top_row, bottom_row, middle, middle_row;
125 ladel_double d22_old;
126 ladel_sparse_matrix *L = LD->L;
127 ladel_int *etree = sym->etree;
128
129 if (LD->pinv != NULL) row_in_L = LD->pinv[row_in_L];
130
131 /* 1. Delete row_in_L l12 */
132 for (col = 0; col < row_in_L; col++)
133 {
134 if (L->nz[col] == 0) continue;
135 /* Perform binary search between top and bottom of col to look for row row_in_L */
136 top = L->p[col];
137 top_row = L->i[top];
138 bottom = L->p[col] + L->nz[col] - 1;
139 bottom_row = L->i[bottom];
140
141 found = FALSE;
142 if (top_row == row_in_L)
143 {
144 index_of_row_in_L = top;
145 found = TRUE;
146 } else if (bottom_row == row_in_L)
147 {
148 index_of_row_in_L = bottom;
149 found = TRUE;
150 } else if (bottom_row < row_in_L || top_row > row_in_L)
151 {
152 continue;
153 } else
154 {
155 while (top < bottom)
156 {
157 middle = (top + bottom)/2;
158 middle_row = L->i[middle];
159 if (middle_row == row_in_L)
160 {
161 index_of_row_in_L = middle;
162 found = TRUE;
163 break;
164 } else if (middle_row > row_in_L)
165 {
166 bottom = middle - 1;
167 } else
168 {
169 top = middle + 1;
170 }
171 }
172
173 middle = (top + bottom)/2;
174 middle_row = L->i[middle];
175 if (middle_row == row_in_L)
176 {
177 index_of_row_in_L = middle;
178 found = TRUE;
179 }
180 }
181 if (found == TRUE)
182 {
183 /* Delete the entry at index_of_row_in_L and move the rest of the column one position up. */
184 for (index = index_of_row_in_L; index < L->p[col] + L->nz[col] - 1; index++)
185 {
186 L->i[index] = L->i[index+1];
187 L->x[index] = L->x[index+1];
188 }
189 L->nz[col]--;
190
191 /* Adjust the etree accordingly. */
192 if (etree[col] == row_in_L)
193 {
194 if (index_of_row_in_L < L->p[col] + L->nz[col]) etree[col] = L->i[index_of_row_in_L];
195 else etree[col] = NONE;
196 }
197 }
198 }
199
200 /* 2. d22_new = 1 */
201 d22_old = 1.0/LD->Dinv[row_in_L];
202 LD->Dinv[row_in_L] = 1;
203
204 /* 4. w = l32_old*sqrt(d22_old) */
205 /* 5. Update or downdate L33*D33*L33^T = L33*D33*L33^T + sign(d22_old)*w*w^T */
206 status = ladel_rank1_update(LD, sym, L, row_in_L, sqrt(LADEL_ABS(d22_old)), d22_old > 0, work);
207 /* 3. Delete column l32 */
208 L->nz[row_in_L] = 0;
209 etree[row_in_L] = NONE;
210
211 return status;
212}
#define NONE
Indicates a root (a node without parent), or an untouched node.
#define TRUE
For booleans.
#define FALSE
For booleans.
#define FAIL
For status returns.
#define LADEL_FOR(index, M, col)
Loop through a column of a sparse matrix.
#define LADEL_ABS(a)
Return the absolute value a number.
ladel_int ladel_row_add(ladel_factor *LD, ladel_symbolics *sym, ladel_int row_in_L, ladel_sparse_matrix *W, ladel_int col_in_W, ladel_double diag, ladel_work *work)
Updates an factorization.
Definition: ladel_row_mod.c:12
ladel_int ladel_row_del(ladel_factor *LD, ladel_symbolics *sym, ladel_int row_in_L, ladel_work *work)
Updates an factorization.
ladel_int ladel_rank1_update(ladel_factor *LD, ladel_symbolics *sym, ladel_sparse_matrix *W, ladel_int col_in_W, ladel_double factor, ladel_int up_or_down, ladel_work *work)
Updates an factorization.
LADEL main include file.
Constants and macros used in LADEL.
void ladel_int_vector_copy(ladel_int *x, ladel_int size, ladel_int *y)
Copies an integer vector (preallocated)
Definition: ladel_copy.c:38
void ladel_double_vector_copy(ladel_double *x, ladel_int size, ladel_double *y)
Copies a double vector (preallocated)
Definition: ladel_copy.c:47
Routines to print out matrices and vectors.
Memory allocation routines.
void ladel_set_set(ladel_set *set, ladel_int *set_vals, ladel_int size_set, ladel_int max_size_set)
Fill in the fields of the given set.
Definition: ladel_global.c:247
Routines to compute the pattern of the result of a backsolve.
ladel_int ladel_etree_dfs(ladel_sparse_matrix *W, ladel_symbolics *sym, ladel_int col_in_W, ladel_int maximum_row)
Computes a depth-first search of the given pattern through the elimination tree.
Definition: ladel_pattern.c:40
Routines to permute vectors and matrices.
void ladel_permute_sparse_vector(ladel_sparse_matrix *x, ladel_int col, ladel_int *p, ladel_work *work)
Permute x(:,col) in place, such that on output .
Helper routines for the rank1_update function.
ladel_int ladel_set_union(ladel_set *first_set, ladel_set *second_set, ladel_set *difference, ladel_int *offset, ladel_int *insertions, ladel_int threshold)
Computes the set union of two index sets.
Routines for the row add/delete updates to a factorization are defined in ladel_row_mod....
Structures and types used in LADEL routines.
int64_t ladel_int
Type for integer numbers (default: int64_t)
Definition: ladel_types.h:24
double ladel_double
Type for floating point numbers (default: double)
Definition: ladel_types.h:20
Sparse matrix in compressed column storage.
Definition: ladel_types.h:35
ladel_double * x
numerical values (size nzmax)
Definition: ladel_types.h:42
ladel_int * p
column pointers (size ncol+1)
Definition: ladel_types.h:40
ladel_int * nz
(optional) number of elements in each column (size ncol)
Definition: ladel_types.h:43
ladel_int * i
row pointers (size nzmax)
Definition: ladel_types.h:41
Set of integers.
Definition: ladel_types.h:81
ladel_int * set
List of integers representing the set.
Definition: ladel_types.h:82
ladel_int size_set
Size of the list.
Definition: ladel_types.h:83
Factors of an factorization.
Definition: ladel_types.h:69
ladel_sparse_matrix * L
L in LDL' factorization.
Definition: ladel_types.h:71
ladel_double * Dinv
D^-1 in LDL' factorization (stored as vector)
Definition: ladel_types.h:73
ladel_int * pinv
inverse permutation vector
Definition: ladel_types.h:75
Structure capturing symbolic information used for and during the factorization.
Definition: ladel_types.h:54
ladel_int ncol
number of columns in the analyzed matrix
Definition: ladel_types.h:55
ladel_int * pattern
stores the nonzero pattern of a row of L
Definition: ladel_types.h:61
ladel_int * etree
eliminations tree
Definition: ladel_types.h:56
Workspace required for various routines in LADEL.
Definition: ladel_types.h:109
ladel_int * array_int_ncol2
An array of ncol integers.
Definition: ladel_types.h:117
ladel_set * set_preallocated2
A preallocated set structure.
Definition: ladel_types.h:111
ladel_int * array_int_ncol1
An array of ncol integers.
Definition: ladel_types.h:116
ladel_int * array_int_ncol3
An array of ncol integers.
Definition: ladel_types.h:118
ladel_set * set_unallocated_values2
An unallocated set structure.
Definition: ladel_types.h:114
ladel_double * array_double_all_zeros_ncol1
An array of ncol doubles, on input and output this should be all zeros.
Definition: ladel_types.h:122
ladel_set * set_preallocated1
A preallocated set structure.
Definition: ladel_types.h:110
ladel_double * array_double_ncol1
An array of ncol doubles.
Definition: ladel_types.h:123