/* The implementation is based on Section 5.2 of Michael Karr, * "Affine Relationships Among Variables of a Program", * except that the echelon form we use starts from the last column * and that we are dealing with integer coefficients. */ static struct isl_basic_set *affine_hull( struct isl_basic_set *bset1, struct isl_basic_set *bset2) { unsigned total; int col; int row; if (!bset1 || !bset2) goto error; total = 1 + isl_basic_set_n_dim(bset1); row = 0; for (col = total-1; col >= 0; --col) { int is_zero1 = row >= bset1->n_eq || isl_int_is_zero(bset1->eq[row][col]); int is_zero2 = row >= bset2->n_eq || isl_int_is_zero(bset2->eq[row][col]); if (!is_zero1 && !is_zero2) { set_common_multiple(bset1, bset2, row, col); ++row; } else if (!is_zero1 && is_zero2) { construct_column(bset1, bset2, row, col); } else if (is_zero1 && !is_zero2) { construct_column(bset2, bset1, row, col); } else { if (transform_column(bset1, bset2, row, col)) --row; } } isl_assert(bset1->ctx, row == bset1->n_eq, goto error); isl_basic_set_free(bset2); bset1 = isl_basic_set_normalize_constraints(bset1); return bset1; error: isl_basic_set_free(bset1); isl_basic_set_free(bset2); return NULL; }
size_t TRILINOS_KLU_kernel /* final size of LU on output */ ( /* input, not modified */ Int n, /* A is n-by-n */ Int Ap [ ], /* size n+1, column pointers for A */ Int Ai [ ], /* size nz = Ap [n], row indices for A */ Entry Ax [ ], /* size nz, values of A */ Int Q [ ], /* size n, optional input permutation */ size_t lusize, /* initial size of LU on input */ /* output, not defined on input */ Int Pinv [ ], /* size n, inverse row permutation, where Pinv [i] = k if * row i is the kth pivot row */ Int P [ ], /* size n, row permutation, where P [k] = i if row i is the * kth pivot row. */ Unit **p_LU, /* LU array, size lusize on input */ Entry Udiag [ ], /* size n, diagonal of U */ Int Llen [ ], /* size n, column length of L */ Int Ulen [ ], /* size n, column length of U */ Int Lip [ ], /* size n, column pointers for L */ Int Uip [ ], /* size n, column pointers for U */ Int *lnz, /* size of L*/ Int *unz, /* size of U*/ /* workspace, not defined on input */ Entry X [ ], /* size n, undefined on input, zero on output */ /* workspace, not defined on input or output */ Int Stack [ ], /* size n */ Int Flag [ ], /* size n */ Int Ap_pos [ ], /* size n */ /* other workspace: */ Int Lpend [ ], /* size n workspace, for pruning only */ /* inputs, not modified on output */ Int k1, /* the block of A is from k1 to k2-1 */ Int PSinv [ ], /* inverse of P from symbolic factorization */ double Rs [ ], /* scale factors for A */ /* inputs, modified on output */ Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ Int Offi [ ], Entry Offx [ ], /* --------------- */ TRILINOS_KLU_common *Common ) { Entry pivot ; double abs_pivot, xsize, nunits, tol, memgrow ; Entry *Ux ; Int *Li, *Ui ; Unit *LU ; /* LU factors (pattern and values) */ Int k, p, i, j, pivrow, kbar, diagrow, firstrow, lup, top, scale, len ; size_t newlusize ; #ifndef NDEBUG Entry *Lx ; #endif ASSERT (Common != NULL) ; scale = Common->scale ; tol = Common->tol ; memgrow = Common->memgrow ; *lnz = 0 ; *unz = 0 ; /* ---------------------------------------------------------------------- */ /* get initial Li, Lx, Ui, and Ux */ /* ---------------------------------------------------------------------- */ PRINTF (("input: lusize %d \n", lusize)) ; ASSERT (lusize > 0) ; LU = *p_LU ; /* ---------------------------------------------------------------------- */ /* initializations */ /* ---------------------------------------------------------------------- */ firstrow = 0 ; lup = 0 ; for (k = 0 ; k < n ; k++) { /* X [k] = 0 ; */ CLEAR (X [k]) ; Flag [k] = EMPTY ; Lpend [k] = EMPTY ; /* flag k as not pruned */ } /* ---------------------------------------------------------------------- */ /* mark all rows as non-pivotal and determine initial diagonal mapping */ /* ---------------------------------------------------------------------- */ /* PSinv does the symmetric permutation, so don't do it here */ for (k = 0 ; k < n ; k++) { P [k] = k ; Pinv [k] = FLIP (k) ; /* mark all rows as non-pivotal */ } /* initialize the construction of the off-diagonal matrix */ Offp [0] = 0 ; /* P [k] = row means that UNFLIP (Pinv [row]) = k, and visa versa. * If row is pivotal, then Pinv [row] >= 0. A row is initially "flipped" * (Pinv [k] < EMPTY), and then marked "unflipped" when it becomes * pivotal. */ #ifndef NDEBUG for (k = 0 ; k < n ; k++) { PRINTF (("Initial P [%d] = %d\n", k, P [k])) ; } #endif /* ---------------------------------------------------------------------- */ /* factorize */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n ; k++) { PRINTF (("\n\n==================================== k: %d\n", k)) ; /* ------------------------------------------------------------------ */ /* determine if LU factors have grown too big */ /* ------------------------------------------------------------------ */ /* (n - k) entries for L and k entries for U */ nunits = DUNITS (Int, n - k) + DUNITS (Int, k) + DUNITS (Entry, n - k) + DUNITS (Entry, k) ; /* LU can grow by at most 'nunits' entries if the column is dense */ PRINTF (("lup %d lusize %g lup+nunits: %g\n", lup, (double) lusize, lup+nunits)); xsize = ((double) lup) + nunits ; if (xsize > (double) lusize) { /* check here how much to grow */ xsize = (memgrow * ((double) lusize) + 4*n + 1) ; if (INT_OVERFLOW (xsize)) { PRINTF (("Matrix is too large (Int overflow)\n")) ; Common->status = TRILINOS_KLU_TOO_LARGE ; return (lusize) ; } newlusize = memgrow * lusize + 2*n + 1 ; /* Future work: retry mechanism in case of malloc failure */ LU = (Unit*) TRILINOS_KLU_realloc (newlusize, lusize, sizeof (Unit), LU, Common) ; Common->nrealloc++ ; *p_LU = LU ; if (Common->status == TRILINOS_KLU_OUT_OF_MEMORY) { PRINTF (("Matrix is too large (LU)\n")) ; return (lusize) ; } lusize = newlusize ; PRINTF (("inc LU to %d done\n", lusize)) ; } /* ------------------------------------------------------------------ */ /* start the kth column of L and U */ /* ------------------------------------------------------------------ */ Lip [k] = lup ; /* ------------------------------------------------------------------ */ /* compute the nonzero pattern of the kth column of L and U */ /* ------------------------------------------------------------------ */ #ifndef NDEBUG for (i = 0 ; i < n ; i++) { ASSERT (Flag [i] < k) ; /* ASSERT (X [i] == 0) ; */ ASSERT (IS_ZERO (X [i])) ; } #endif top = lsolve_symbolic (n, k, Ap, Ai, Q, Pinv, Stack, Flag, Lpend, Ap_pos, LU, lup, Llen, Lip, k1, PSinv) ; #ifndef NDEBUG PRINTF (("--- in U:\n")) ; for (p = top ; p < n ; p++) { PRINTF (("pattern of X for U: %d : %d pivot row: %d\n", p, Stack [p], Pinv [Stack [p]])) ; ASSERT (Flag [Stack [p]] == k) ; } PRINTF (("--- in L:\n")) ; Li = (Int *) (LU + Lip [k]); for (p = 0 ; p < Llen [k] ; p++) { PRINTF (("pattern of X in L: %d : %d pivot row: %d\n", p, Li [p], Pinv [Li [p]])) ; ASSERT (Flag [Li [p]] == k) ; } p = 0 ; for (i = 0 ; i < n ; i++) { ASSERT (Flag [i] <= k) ; if (Flag [i] == k) p++ ; } #endif /* ------------------------------------------------------------------ */ /* get the column of the matrix to factorize and scatter into X */ /* ------------------------------------------------------------------ */ construct_column (k, Ap, Ai, Ax, Q, X, k1, PSinv, Rs, scale, Offp, Offi, Offx) ; /* ------------------------------------------------------------------ */ /* compute the numerical values of the kth column (s = L \ A (:,k)) */ /* ------------------------------------------------------------------ */ lsolve_numeric (Pinv, LU, Stack, Lip, top, n, Llen, X) ; #ifndef NDEBUG for (p = top ; p < n ; p++) { PRINTF (("X for U %d : ", Stack [p])) ; PRINT_ENTRY (X [Stack [p]]) ; } Li = (Int *) (LU + Lip [k]) ; for (p = 0 ; p < Llen [k] ; p++) { PRINTF (("X for L %d : ", Li [p])) ; PRINT_ENTRY (X [Li [p]]) ; } #endif /* ------------------------------------------------------------------ */ /* partial pivoting with diagonal preference */ /* ------------------------------------------------------------------ */ /* determine what the "diagonal" is */ diagrow = P [k] ; /* might already be pivotal */ PRINTF (("k %d, diagrow = %d, UNFLIP (diagrow) = %d\n", k, diagrow, UNFLIP (diagrow))) ; /* find a pivot and scale the pivot column */ if (!lpivot (diagrow, &pivrow, &pivot, &abs_pivot, tol, X, LU, Lip, Llen, k, n, Pinv, &firstrow, Common)) { /* matrix is structurally or numerically singular */ Common->status = TRILINOS_KLU_SINGULAR ; if (Common->numerical_rank == EMPTY) { Common->numerical_rank = k+k1 ; Common->singular_col = Q [k+k1] ; } if (Common->halt_if_singular) { /* do not continue the factorization */ return (lusize) ; } } /* we now have a valid pivot row, even if the column has NaN's or * has no entries on or below the diagonal at all. */ PRINTF (("\nk %d : Pivot row %d : ", k, pivrow)) ; PRINT_ENTRY (pivot) ; ASSERT (pivrow >= 0 && pivrow < n) ; ASSERT (Pinv [pivrow] < 0) ; /* set the Uip pointer */ Uip [k] = Lip [k] + UNITS (Int, Llen [k]) + UNITS (Entry, Llen [k]) ; /* move the lup pointer to the position where indices of U * should be stored */ lup += UNITS (Int, Llen [k]) + UNITS (Entry, Llen [k]) ; Ulen [k] = n - top ; /* extract Stack [top..n-1] to Ui and the values to Ux and clear X */ GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; for (p = top, i = 0 ; p < n ; p++, i++) { j = Stack [p] ; Ui [i] = Pinv [j] ; Ux [i] = X [j] ; CLEAR (X [j]) ; } /* position the lu index at the starting point for next column */ lup += UNITS (Int, Ulen [k]) + UNITS (Entry, Ulen [k]) ; /* U(k,k) = pivot */ Udiag [k] = pivot ; /* ------------------------------------------------------------------ */ /* log the pivot permutation */ /* ------------------------------------------------------------------ */ ASSERT (UNFLIP (Pinv [diagrow]) < n) ; ASSERT (P [UNFLIP (Pinv [diagrow])] == diagrow) ; if (pivrow != diagrow) { /* an off-diagonal pivot has been chosen */ Common->noffdiag++ ; PRINTF ((">>>>>>>>>>>>>>>>> pivrow %d k %d off-diagonal\n", pivrow, k)) ; if (Pinv [diagrow] < 0) { /* the former diagonal row index, diagrow, has not yet been * chosen as a pivot row. Log this diagrow as the "diagonal" * entry in the column kbar for which the chosen pivot row, * pivrow, was originally logged as the "diagonal" */ kbar = FLIP (Pinv [pivrow]) ; P [kbar] = diagrow ; Pinv [diagrow] = FLIP (kbar) ; } } P [k] = pivrow ; Pinv [pivrow] = k ; #ifndef NDEBUG for (i = 0 ; i < n ; i++) { ASSERT (IS_ZERO (X [i])) ;} GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; for (p = 0 ; p < len ; p++) { PRINTF (("Column %d of U: %d : ", k, Ui [p])) ; PRINT_ENTRY (Ux [p]) ; } GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; for (p = 0 ; p < len ; p++) { PRINTF (("Column %d of L: %d : ", k, Li [p])) ; PRINT_ENTRY (Lx [p]) ; } #endif /* ------------------------------------------------------------------ */ /* symmetric pruning */ /* ------------------------------------------------------------------ */ prune (Lpend, Pinv, k, pivrow, LU, Uip, Lip, Ulen, Llen) ; *lnz += Llen [k] + 1 ; /* 1 added to lnz for diagonal */ *unz += Ulen [k] + 1 ; /* 1 added to unz for diagonal */ } /* ---------------------------------------------------------------------- */ /* finalize column pointers for L and U, and put L in the pivotal order */ /* ---------------------------------------------------------------------- */ for (p = 0 ; p < n ; p++) { Li = (Int *) (LU + Lip [p]) ; for (i = 0 ; i < Llen [p] ; i++) { Li [i] = Pinv [Li [i]] ; } } #ifndef NDEBUG for (i = 0 ; i < n ; i++) { PRINTF (("P [%d] = %d Pinv [%d] = %d\n", i, P [i], i, Pinv [i])) ; } for (i = 0 ; i < n ; i++) { ASSERT (Pinv [i] >= 0 && Pinv [i] < n) ; ASSERT (P [i] >= 0 && P [i] < n) ; ASSERT (P [Pinv [i]] == i) ; ASSERT (IS_ZERO (X [i])) ; } #endif /* ---------------------------------------------------------------------- */ /* shrink the LU factors to just the required size */ /* ---------------------------------------------------------------------- */ newlusize = lup ; ASSERT ((size_t) newlusize <= lusize) ; /* this cannot fail, since the block is descreasing in size */ LU = (Unit*) TRILINOS_KLU_realloc (newlusize, lusize, sizeof (Unit), LU, Common) ; *p_LU = LU ; return (newlusize) ; }