Rev 1820 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === UMF_local_search ===================================================== *//* ========================================================================== *//* -------------------------------------------------------------------------- *//* UMFPACK Version 4.5, Copyright (c) 2005 by Timothy A. Davis. CISE Dept, *//* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. *//* web: http://www.cise.ufl.edu/research/sparse/umfpack *//* -------------------------------------------------------------------------- *//*Perform pivot search to find pivot row and pivot column.The pivot column is selected from the candidate set. The candidate setcorresponds to a supercolumn from colamd or UMF_analyze. The pivot columnis then removed from that set. Constructs the pivot column pattern andvalues. Called by umf_kernel. Returns UMFPACK_OK if successful, orUMFPACK_WARNING_singular_matrix or UMFPACK_ERROR_different_pattern if not.*/#include "umf_internal.h"#include "umf_row_search.h"#include "umf_mem_free_tail_block.h"/* relaxed amalgamation control parameters are fixed at compile time */#define RELAX1 0.25#define SYM_RELAX1 0.0#define RELAX2 0.1#define RELAX3 0.125/* ========================================================================== *//* === remove_candidate ===================================================== *//* ========================================================================== *//* Remove a column from the set of candidate pivot columns. */PRIVATE void remove_candidate (Int jj, WorkType *Work, SymbolicType *Symbolic){#ifndef NDEBUGInt j ;DEBUGm2 (("pivot column Candidates before remove: nCand "ID" ncand "ID" lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand,Work->lo, Work->hi, jj)) ;for (j = 0 ; j < Work->nCandidates ; j++){Int col = Work->Candidates [j] ;DEBUGm2 ((ID" ", col));ASSERT (col >= 0 && col < Work->n_col) ;/* ASSERT (NON_PIVOTAL_COL (col)) ; */ASSERT (col >= Work->lo && col <= Work->hi) ;}DEBUGm2 (("\n")) ;#endifif (Symbolic->fixQ){DEBUGm2 (("FixQ\n")) ;/* do not modify the column ordering */ASSERT (Work->nCandidates == 1) ;ASSERT (jj == 0) ;if (Work->ncand > 1){Work->Candidates [0] = Work->nextcand++ ;}else{Work->nCandidates = 0 ;}}else{/* place the next candidate in the set */if (Work->ncand > MAX_CANDIDATES){Work->Candidates [jj] = Work->nextcand++ ;}else{ASSERT (Work->nCandidates == Work->ncand) ;Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ;Work->Candidates [Work->ncand - 1] = EMPTY ;Work->nCandidates-- ;}}Work->ncand-- ;#ifndef NDEBUGDEBUGm2 (("pivot column Candidates after remove: nCand "ID" ncand "ID" lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo,Work->hi, jj)) ;for (j = 0 ; j < Work->nCandidates ; j++){Int col = Work->Candidates [j] ;DEBUGm2 ((ID" ", col));ASSERT (col >= 0 && col < Work->n_col) ;/* ASSERT (NON_PIVOTAL_COL (col)) ; */ASSERT (col >= Work->lo && col <= Work->hi) ;}DEBUGm2 (("\n")) ;ASSERT (Work->ncand >= 0) ;ASSERT (Work->nCandidates <= Work->ncand) ;#endif}/* ========================================================================== *//* === UMF_local_search ===================================================== *//* ========================================================================== */GLOBAL Int UMF_local_search(NumericType *Numeric,WorkType *Work,SymbolicType *Symbolic){/* ---------------------------------------------------------------------- *//* local variables *//* ---------------------------------------------------------------------- */double relax1 ;Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock,*Flu ;Int pos, nrows, *Cols, *Rows, e, f, status, max_cdeg, fnzeros, nb, j, col,i, row, cdeg_in, rdeg [2][2], fnpiv, nothing [2], new_LUsize,pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros, cdeg_out,*Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E, deg, nr_in,nc, thiscost, bestcost, nr_out, do_update, extra_cols, extra_rows,extra_zeros, relaxed_front, do_extend, fnr_curr, fnc_curr, tpi,*Col_tuples, *Col_degree, *Col_tlen, jj, jcand [2], freebie [2],did_rowmerge, fnrows_new [2][2], fncols_new [2][2], search_pivcol_out,*Diagonal_map, *Diagonal_imap, row2, col2 ;Unit *Memory, *p ;Tuple *tp, *tpend, *tp1, *tp2 ;Element *ep ;#ifndef NDEBUGInt debug_ok, n_row, n_col, *Row_degree ;Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro only */#endif/* ---------------------------------------------------------------------- *//* get parameters *//* ---------------------------------------------------------------------- */Memory = Numeric->Memory ;E = Work->E ;Col_degree = Numeric->Cperm ;Col_tuples = Numeric->Lip ;Col_tlen = Numeric->Lilen ;Wx = Work->Wx ;Wy = Work->Wy ;Wp = Work->Wp ;Wm = Work->Wm ;Woi = Work->Woi ;Wio = Work->Wio ;Woo = Work->Woo ;Fcpos = Work->Fcpos ;Frpos = Work->Frpos ;Frows = Work->Frows ;Fcols = Work->Fcols ;fnrows = Work->fnrows ;fncols = Work->fncols ;nb = Work->nb ;fnr_curr = Work->fnr_curr ;fnc_curr = Work->fnc_curr ;fnpiv = Work->fnpiv ;nothing [0] = EMPTY ;nothing [1] = EMPTY ;relax1 = (Symbolic->prefer_diagonal) ? SYM_RELAX1 : RELAX1 ;fnzeros = Work->fnzeros ;new_fnzeros = fnzeros ;jj = EMPTY ;Fcblock = Work->Fcblock ; /* current contribution block */Flblock = Work->Flblock ; /* current L block */Fublock = Work->Fublock ; /* current U block */Flublock = Work->Flublock ; /* current LU block *//* The pivot column degree cannot exceed max_cdeg */max_cdeg = Work->fnrows_max ;ASSERT (Work->fnrows_max <= Symbolic->maxnrows) ;ASSERT (Work->fncols_max <= Symbolic->maxncols) ;if (fnrows == 0 && fncols == 0){/* frontal matrix is empty */Work->firstsuper = Work->ksuper ;}#ifndef NDEBUGn_row = Work->n_row ;n_col = Work->n_col ;DEBUG2 (("\n========LOCAL SEARCH: current frontal matrix: ========= \n")) ;UMF_dump_current_front (Numeric, Work, TRUE) ;if (UMF_debug > 0 || MAX (n_row, n_col) < 1000){for (i = 0 ; i < MAX (n_row, n_col) ; i++){ASSERT (Wp [i] < 0) ;}}DEBUGm2 ((ID" pivot column Candidates: lo "ID" hi "ID"\n",Work->nCandidates, Work->lo, Work->hi)) ;for (j = 0 ; j < Work->nCandidates ; j++){col = Work->Candidates [j] ;DEBUGm2 ((ID" ", col));ASSERT (col >= 0 && col < n_col) ;ASSERT (NON_PIVOTAL_COL (col)) ;ASSERT (col >= Work->lo && col <= Work->hi) ;}DEBUGm2 (("\n")) ;/* there are no 0-by-c or r-by-0 fronts, where c and r are > 0 *//* a front is either 0-by-0, or r-by-c */DEBUG2 (("\n\n::: "ID" : Npiv: "ID" + fnpiv "ID" = "ID". ""size "ID"-by-"ID"\n", Work->frontid,Work->npiv, Work->fnpiv, Work->npiv + Work->fnpiv, fnrows, fncols)) ;ASSERT ((fnrows == 0 && fncols == 0) ||(fnrows != 0 && fncols != 0)) ;#endif/* ====================================================================== *//* === PIVOT SEARCH ===================================================== *//* ====================================================================== *//* initialize */pivcol [IN] = EMPTY ;pivcol [OUT] = EMPTY ;cdeg_in = Int_MAX ;cdeg_out = Int_MAX ;pivrow [IN][IN] = EMPTY ;pivrow [IN][OUT] = EMPTY ;pivrow [OUT][IN] = EMPTY ;pivrow [OUT][OUT] = EMPTY ;rdeg [IN][IN] = Int_MAX ;rdeg [IN][OUT] = Int_MAX ;rdeg [OUT][IN] = Int_MAX ;rdeg [OUT][OUT] = Int_MAX ;freebie [IN] = FALSE ;freebie [OUT] = FALSE ;Work->pivot_case = EMPTY ;bestcost = EMPTY ;nr_out = EMPTY ;nr_in = EMPTY ;jcand [IN] = EMPTY ;jcand [OUT] = EMPTY ;fnrows_new [IN][IN] = EMPTY ;fnrows_new [IN][OUT] = EMPTY ;fnrows_new [OUT][IN] = EMPTY ;fnrows_new [OUT][OUT] = EMPTY ;fncols_new [IN][IN] = EMPTY ;fncols_new [IN][OUT] = EMPTY ;fncols_new [OUT][IN] = EMPTY ;fncols_new [OUT][OUT] = EMPTY ;#ifndef NDEBUG/* check Frpos */DEBUG4 (("Check Frpos : fnrows "ID" col "ID" maxcdeg "ID"\n",fnrows, pivcol [IN], max_cdeg)) ;for (i = 0 ; i < fnrows ; i++){row = Frows [i] ;DEBUG4 ((" row: "ID"\n", row)) ;ASSERT (row >= 0 && row < n_row) ;ASSERT (Frpos [row] == i) ;}DEBUG4 (("All:\n")) ;if (UMF_debug > 0 || n_row < 1000){Int cnt = fnrows ;for (row = 0 ; row < n_row ; row++){if (Frpos [row] == EMPTY){cnt++ ;}else{DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;}}ASSERT (cnt == n_row) ;}#endif/* ---------------------------------------------------------------------- *//* find shortest column in the front, and shortest column not in the *//* front, from the candidate pivot column set *//* ---------------------------------------------------------------------- *//* If there are too many candidates, then only look at the first *//* MAX_CANDIDATES of them. Otherwise, if there are O(n) candidates, *//* this code could take O(n^2) time. *//* ------------------------------------------------------------------ *//* look in the candidate set for the best column *//* ------------------------------------------------------------------ */DEBUG2 (("Max candidates %d, Work->ncand "ID" jmax "ID"\n",MAX_CANDIDATES, Work->ncand, Work->nCandidates)) ;col = Work->Candidates [0] ;ASSERT (Work->nCandidates > 0) ;DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;ASSERT (col >= 0 && col < n_col) ;/* there is no Col_degree if fixQ is true */deg = Symbolic->fixQ ? EMPTY : Col_degree [col] ;#ifndef NDEBUGDEBUG3 (("Pivot column candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",col, deg, Fcpos [col])) ;UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;if (Symbolic->fixQ){DEBUG1 (("FIXQ: Candidates "ID" pivcol "ID" npiv "ID" fnpiv "ID" ndiscard "ID "\n", Work->nCandidates, col, Work->npiv,Work->fnpiv, Work->ndiscard)) ;ASSERT (Work->nCandidates == 1) ;ASSERT (col == Work->npiv + Work->fnpiv + Work->ndiscard) ;}#endifif (Fcpos [col] >= 0){/* best column in front, so far */pivcol [IN] = col ;cdeg_in = deg ; /* ignored, if fixQ is true */jcand [IN] = 0 ;}else{/* best column not in front, so far */pivcol [OUT] = col ;cdeg_out = deg ; /* ignored, if fixQ is true */jcand [OUT] = 0 ;}/* look at the rest of the candidates */for (j = 1 ; j < Work->nCandidates ; j++){col = Work->Candidates [j] ;DEBUG3 (("Pivot col candidate: "ID" j = "ID"\n", col, j)) ;ASSERT (col >= 0 && col < n_col) ;ASSERT (!Symbolic->fixQ) ;deg = Col_degree [col] ;#ifndef NDEBUGDEBUG3 (("Pivot col candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",col, deg, Fcpos [col])) ;UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;#endifif (Fcpos [col] >= 0){#ifndef NDEBUGInt fs ;fs = Fcpos [col] / fnr_curr ;ASSERT (fs >= 0 && fs < fncols) ;#endifif (deg < cdeg_in || (deg == cdeg_in && col < pivcol [IN])){/* best column in front, so far */pivcol [IN] = col ;cdeg_in = deg ;jcand [IN] = j ;}}else{if (deg < cdeg_out || (deg == cdeg_out && col < pivcol [OUT])){/* best column not in front, so far */pivcol [OUT] = col ;cdeg_out = deg ;jcand [OUT] = j ;}}}DEBUG2 (("Pivcol in "ID" out "ID"\n", pivcol [IN], pivcol [OUT])) ;ASSERT ((pivcol [IN] >= 0 && pivcol [IN] < n_col)|| (pivcol [OUT] >= 0 && pivcol [OUT] < n_col)) ;cdeg_in = EMPTY ;cdeg_out = EMPTY ;/* ---------------------------------------------------------------------- *//* construct candidate column in front, and search for pivot rows *//* ---------------------------------------------------------------------- */#ifndef NDEBUG/* check Frpos */DEBUG4 (("Prior to col update: fnrows "ID" col "ID" maxcdeg "ID"\n",fnrows, pivcol [IN], max_cdeg)) ;for (i = 0 ; i < fnrows ; i++){row = Frows [i] ;DEBUG4 ((" row: "ID"\n", row)) ;ASSERT (row >= 0 && row < n_row) ;ASSERT (Frpos [row] == i) ;}DEBUG4 (("All:\n")) ;if (UMF_debug > 0 || n_row < 1000){Int cnt = fnrows ;for (row = 0 ; row < n_row ; row++){if (Frpos [row] == EMPTY){cnt++ ;}else{DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;}}ASSERT (cnt == n_row) ;}#endifif (pivcol [IN] != EMPTY){#ifndef NDEBUGDEBUG2 (("col[IN] column "ID" in front at position = "ID"\n",pivcol [IN], Fcpos [pivcol [IN]])) ;UMF_dump_rowcol (1, Numeric, Work, pivcol [IN], !Symbolic->fixQ) ;#endif/* the only way we can have a pivcol[IN] is if the front is not empty */ASSERT (fnrows > 0 && fncols > 0) ;DEBUG4 (("Update pivot column:\n")) ;Fs = Fcblock + Fcpos [pivcol [IN]] ;Fu = Fublock + (Fcpos [pivcol [IN]] / fnr_curr) ;Flu = Flublock + fnpiv * nb ;/* ------------------------------------------------------------------ *//* copy the pivot column from the U block into the LU block *//* ------------------------------------------------------------------ *//* This copy is permanent if the pivcol [IN] is chosen. */for (i = 0 ; i < fnpiv ; i++){Flu [i] = Fu [i*fnc_curr] ;}/* ------------------------------------------------------------------ *//* update the pivot column in the LU block using a triangular solve *//* ------------------------------------------------------------------ *//* This work will be discarded if the pivcol [OUT] is chosen instead.* It is permanent if the pivcol [IN] is chosen. */if (fnpiv > 1){/* solve Lx=b, where b = U (:,k), stored in the LU block */#ifdef USE_NO_BLAS/* no BLAS available - use plain C code instead */Entry *Flub = Flublock ;for (j = 0 ; j < fnpiv ; j++){Entry Fuj = Flu [j] ;#pragma ivdepfor (i = j+1 ; i < fnpiv ; i++){/* Flu [i] -= Flublock [i + j*nb] * Flu [j] ; */MULT_SUB (Flu [i], Flub [i], Fuj) ;}Flub += nb ;}#elseBLAS_TRSV (fnpiv, Flublock, Flu, nb) ;#endif}/* ------------------------------------------------------------------ *//* copy the pivot column from the C block into Wy *//* ------------------------------------------------------------------ */for (i = 0 ; i < fnrows ; i++){Wy [i] = Fs [i] ;}/* ------------------------------------------------------------------ *//* update the pivot column of L using a matrix-vector multiply *//* ------------------------------------------------------------------ *//* this work will be discarded if the pivcol [OUT] is chosen instead */#ifdef USE_NO_BLAS/* no BLAS available - use plain C code instead */for (j = 0 ; j < fnpiv ; j++){Entry Fuj, *Flub = Flblock + j * fnr_curr ;Fuj = Flu [j] ;if (IS_NONZERO (Fuj)){#pragma ivdepfor (i = 0 ; i < fnrows ; i++){/* Wy [i] -= Flblock [i+j*fnr_curr] * Fuj ; */MULT_SUB (Wy [i], Flub [i], Fuj) ;}}/* Flblock += fnr_curr ; */}#else/* Using 1-based notation:* Wy (1:fnrows) -= Flblock (1:fnrows,1:fnpiv) * Flu (1:fnpiv) */BLAS_GEMV (fnrows, fnpiv, Flblock, Flu, Wy, fnr_curr) ;#endif/* ------------------------------------------------------------------ */#ifndef NDEBUGDEBUG2 (("Wy after update: fnrows="ID"\n", fnrows)) ;DEBUG4 ((" fnpiv="ID" \n", fnpiv)) ;for (i = 0 ; i < fnrows ; i++){DEBUG4 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;EDEBUG4 (Wy [i]) ;DEBUG4 (("\n")) ;}#endif/* ------------------------------------------------------------------ *//* construct the candidate column *//* ------------------------------------------------------------------ */cdeg_in = fnrows ;#ifndef NDEBUG/* check Frpos */DEBUG4 (("After col update: fnrows "ID" col "ID" maxcdeg "ID"\n",fnrows, pivcol [IN], max_cdeg)) ;for (i = 0 ; i < fnrows ; i++){row = Frows [i] ;DEBUG4 ((" row: "ID"\n", row)) ;ASSERT (row >= 0 && row < n_row) ;ASSERT (Frpos [row] == i) ;}DEBUG4 (("All:\n")) ;if (UMF_debug > 0 || n_row < 1000){Int cnt = fnrows ;for (row = 0 ; row < n_row ; row++){if (Frpos [row] == EMPTY){cnt++ ;}else{DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;}}ASSERT (cnt == n_row) ;}#endif#ifndef NDEBUG/* check Frpos */DEBUG4 (("COL ASSEMBLE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",cdeg_in, pivcol [IN], max_cdeg)) ;for (i = 0 ; i < cdeg_in ; i++){row = Frows [i] ;ASSERT (row >= 0 && row < n_row) ;ASSERT (Frpos [row] == i) ;}if (UMF_debug > 0 || n_row < 1000){Int cnt = cdeg_in ;for (row = 0 ; row < n_row ; row++){if (Frpos [row] == EMPTY) cnt++ ;}ASSERT (cnt == n_row) ;}#endif/* assemble column into Wy */ASSERT (pivcol [IN] >= 0 && pivcol [IN] < n_col) ;ASSERT (NON_PIVOTAL_COL (pivcol [IN])) ;tpi = Col_tuples [pivcol [IN]] ;if (tpi){tp = (Tuple *) (Memory + tpi) ;tp1 = tp ;tp2 = tp ;tpend = tp + Col_tlen [pivcol [IN]] ;for ( ; tp < tpend ; tp++){e = tp->e ;ASSERT (e > 0 && e <= Work->nel) ;if (!E [e]) continue ; /* element already deallocated */f = tp->f ;p = Memory + E [e] ;ep = (Element *) p ;p += UNITS (Element, 1) ;Cols = (Int *) p ;if (Cols [f] == EMPTY) continue ; /* column already assembled */ASSERT (pivcol [IN] == Cols [f]) ;Rows = Cols + ep->ncols ;nrows = ep->nrows ;p += UNITS (Int, ep->ncols + nrows) ;C = ((Entry *) p) + f * nrows ;for (i = 0 ; i < nrows ; i++){row = Rows [i] ;if (row >= 0) /* skip this if already gone from element */{ASSERT (row < n_row) ;pos = Frpos [row] ;if (pos < 0){/* new entry in the pattern - save Frpos */ASSERT (cdeg_in < n_row) ;if (cdeg_in >= max_cdeg){/* :: pattern change (cdeg in failure) :: */DEBUGm4 (("cdeg_in failure\n")) ;return (UMFPACK_ERROR_different_pattern) ;}Frpos [row] = cdeg_in ;Frows [cdeg_in] = row ;Wy [cdeg_in++] = C [i] ;}else{/* entry already in pattern - sum values in Wy *//* Wy [pos] += C [i] ; */ASSERT (pos < max_cdeg) ;ASSEMBLE (Wy [pos], C [i]) ;}}}*tp2++ = *tp ; /* leave the tuple in the list */}Col_tlen [pivcol [IN]] = tp2 - tp1 ;}/* ------------------------------------------------------------------ */#ifndef NDEBUG/* check Frpos again */DEBUG4 (("COL DONE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",cdeg_in, pivcol [IN], max_cdeg)) ;for (i = 0 ; i < cdeg_in ; i++){row = Frows [i] ;ASSERT (row >= 0 && row < n_row) ;ASSERT (Frpos [row] == i) ;}if (UMF_debug > 0 || n_row < 1000){Int cnt = cdeg_in ;for (row = 0 ; row < n_row ; row++){if (Frpos [row] == EMPTY) cnt++ ;}ASSERT (cnt == n_row) ;}#endif#ifndef NDEBUGDEBUG4 (("Reduced column: cdeg in "ID" fnrows_max "ID"\n",cdeg_in, Work->fnrows_max)) ;for (i = 0 ; i < cdeg_in ; i++){DEBUG4 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;EDEBUG4 (Wy [i]) ;DEBUG4 (("\n")) ;ASSERT (i == Frpos [Frows [i]]) ;}ASSERT (cdeg_in <= Work->fnrows_max) ;#endif/* ------------------------------------------------------------------ *//* cdeg_in is now the exact degree of this column *//* ------------------------------------------------------------------ */nr_in = cdeg_in - fnrows ;/* since there are no 0-by-x fronts, if there is a pivcol [IN] the *//* front must have at least one row. */ASSERT (cdeg_in > 0) ;/* new degree of pivcol [IN], excluding current front is nr_in *//* column expands by nr_in rows *//* ------------------------------------------------------------------ *//* search for two candidate pivot rows *//* ------------------------------------------------------------------ *//* for the IN_IN pivot row (if any), *//* extend the pattern in place, using Fcols */status = UMF_row_search (Numeric, Work, Symbolic,fnrows, cdeg_in, Frows, Frpos, /* pattern of column to search */pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Wy,pivcol [IN], freebie) ;ASSERT (!freebie [IN] && !freebie [OUT]) ;/* ------------------------------------------------------------------ *//* fatal error if matrix pattern has changed since symbolic analysis *//* ------------------------------------------------------------------ */if (status == UMFPACK_ERROR_different_pattern){/* :: pattern change (row search IN failure) :: */DEBUGm4 (("row search IN failure\n")) ;return (UMFPACK_ERROR_different_pattern) ;}/* ------------------------------------------------------------------ *//* we now must have a structural pivot *//* ------------------------------------------------------------------ *//* Since the pivcol[IN] exists, there must be at least one row in the *//* current frontal matrix, and so we must have found a structural *//* pivot. The numerical value might be zero, of course. */ASSERT (status != UMFPACK_WARNING_singular_matrix) ;/* ------------------------------------------------------------------ *//* evaluate IN_IN option *//* ------------------------------------------------------------------ */if (pivrow [IN][IN] != EMPTY){/* The current front would become an (implicit) LUson.* Both candidate pivot row and column are in the current front.* Cost is how much the current front would expand *//* pivrow[IN][IN] candidates are not found via row merge search */ASSERT (fnrows >= 0 && fncols >= 0) ;ASSERT (cdeg_in > 0) ;nc = rdeg [IN][IN] - fncols ;thiscost =/* each column in front (except pivot column) grows by nr_in: */(nr_in * (fncols - 1)) +/* new columns not in old front: */(nc * (cdeg_in - 1)) ;/* no extra cost to relaxed amalgamation */ASSERT (fnrows + nr_in == cdeg_in) ;ASSERT (fncols + nc == rdeg [IN][IN]) ;/* size of relaxed front (after pivot row column removed): */fnrows_new [IN][IN] = (fnrows-1) + nr_in ;fncols_new [IN][IN] = (fncols-1) + nc ;/* relaxed_front = fnrows_new [IN][IN] * fncols_new [IN][IN] ; */do_extend = TRUE ;DEBUG2 (("Evaluating option IN-IN:\n")) ;DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",Work->fnzeros, fnpiv, nr_in, nc)) ;DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;/* determine if BLAS-3 update should be applied before extending. *//* update if too many zero entries accumulate in the LU block */fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;/* There are fnpiv pivots currently in the front. This one* will be the (fnpiv+1)st pivot, if it is extended. *//* RELAX2 parameter uses a double relop, but ignore NaN case: */do_update = fnpiv > 0 &&(((double) fnzeros) / ((double) new_LUsize)) > RELAX2 ;DEBUG2 (("do_update "ID"\n", do_update))DEBUG2 (("option IN IN : nr "ID" nc "ID" cost "ID"(0) relax "ID"\n", nr_in, nc, thiscost, do_extend)) ;/* this is the best option seen so far */Work->pivot_case = IN_IN ;bestcost = thiscost ;/* do the amalgamation and extend the front */Work->do_extend = do_extend ;Work->do_update = do_update ;new_fnzeros = fnzeros ;}/* ------------------------------------------------------------------ *//* evaluate IN_OUT option *//* ------------------------------------------------------------------ */if (pivrow [IN][OUT] != EMPTY){/* The current front would become a Uson of the new front.* Candidate pivot column is in the current front, but the* candidate pivot row is not. */ASSERT (fnrows >= 0 && fncols > 0) ;ASSERT (cdeg_in > 0) ;/* must be at least one row outside the front *//* (the pivrow [IN][OUT] itself) */ASSERT (nr_in >= 1) ;/* count columns not in current front */nc = 0 ;#ifndef NDEBUGdebug_ok = FALSE ;#endiffor (i = 0 ; i < rdeg [IN][OUT] ; i++){col = Wio [i] ;DEBUG4 (("counting col "ID" Fcpos[] = "ID"\n", col,Fcpos [col])) ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;if (Fcpos [col] < 0) nc++ ;#ifndef NDEBUG/* we must see the pivot column somewhere */if (col == pivcol [IN]){ASSERT (Fcpos [col] >= 0) ;debug_ok = TRUE ;}#endif}ASSERT (debug_ok) ;thiscost =/* each row in front grows by nc: */(nc * fnrows) +/* new rows not affected by front: */((nr_in-1) * (rdeg [IN][OUT]-1)) ;/* check the cost of relaxed IN_OUT amalgamation */extra_cols = ((fncols-1) + nc ) - (rdeg [IN][OUT] - 1) ;ASSERT (extra_cols >= 0) ;ASSERT (fncols + nc == extra_cols + rdeg [IN][OUT]) ;extra_zeros = (nr_in-1) * extra_cols ; /* symbolic fill-in */ASSERT (fnrows + nr_in == cdeg_in) ;ASSERT (fncols + nc == rdeg [IN][OUT] + extra_cols) ;/* size of relaxed front (after pivot column removed): */fnrows_new [IN][OUT] = fnrows + (nr_in-1) ;fncols_new [IN][OUT] = (fncols-1) + nc ;relaxed_front = fnrows_new [IN][OUT] * fncols_new [IN][OUT] ;/* do relaxed amalgamation if the extra zeros are no more *//* than a fraction (default 0.25) of the relaxed front *//* if relax = 0: no extra zeros allowed *//* if relax = +inf: always amalgamate *//* relax parameter uses a double relop, but ignore NaN case: */if (extra_zeros == 0){do_extend = TRUE ;}else{do_extend = ((double) extra_zeros) <(relax1 * (double) relaxed_front) ;}if (do_extend){/* count the cost of relaxed amalgamation */thiscost += extra_zeros ;DEBUG2 (("Evaluating option IN-OUT:\n")) ;DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",Work->fnzeros, fnpiv, nr_in, nc)) ;DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;/* determine if BLAS-3 update to be applied before extending. *//* update if too many zero entries accumulate in the LU block */fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;/* RELAX3 parameter uses a double relop, ignore NaN case: */do_update = fnpiv > 0 &&(((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;DEBUG2 (("do_update "ID"\n", do_update))}else{/* the current front would not be extended */do_update = fnpiv > 0 ;fnzeros = 0 ;DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update)) ;/* The new front would be just big enough to hold the new* pivot row and column. */fnrows_new [IN][OUT] = cdeg_in - 1 ;fncols_new [IN][OUT] = rdeg [IN][OUT] - 1 ;}DEBUG2 (("option IN OUT: nr "ID" nc "ID" cost "ID"("ID") relax "ID"\n", nr_in, nc, thiscost, extra_zeros, do_extend)) ;if (bestcost == EMPTY || thiscost < bestcost){/* this is the best option seen so far */Work->pivot_case = IN_OUT ;bestcost = thiscost ;Work->do_extend = do_extend ;Work->do_update = do_update ;new_fnzeros = fnzeros ;}}}/* ---------------------------------------------------------------------- *//* construct candidate column not in front, and search for pivot rows *//* ---------------------------------------------------------------------- */search_pivcol_out = (bestcost != 0 && pivcol [OUT] != EMPTY) ;if (Symbolic->prefer_diagonal){search_pivcol_out = search_pivcol_out && (pivrow [IN][IN] == EMPTY) ;}if (search_pivcol_out){#ifndef NDEBUGDEBUG2 (("out_col column "ID" NOT in front at position = "ID"\n",pivcol [OUT], Fcpos [pivcol [OUT]])) ;UMF_dump_rowcol (1, Numeric, Work, pivcol [OUT], !Symbolic->fixQ) ;DEBUG2 (("fncols "ID" fncols_max "ID"\n", fncols, Work->fncols_max)) ;ASSERT (fncols < Work->fncols_max) ;#endif/* Use Wx as temporary workspace to construct the pivcol [OUT] *//* ------------------------------------------------------------------ *//* construct the candidate column (currently not in the front) *//* ------------------------------------------------------------------ *//* Construct the column in Wx, Wm, using Wp for the positions: *//* Wm [0..cdeg_out-1] list of row indices in the column *//* Wx [0..cdeg_out-1] list of corresponding numerical values *//* Wp [0..n-1] starts as all negative, and ends that way too. */cdeg_out = 0 ;#ifndef NDEBUG/* check Wp */DEBUG4 (("COL ASSEMBLE: cdeg 0\nREDUCE COL out "ID"\n", pivcol [OUT])) ;if (UMF_debug > 0 || MAX (n_row, n_col) < 1000){for (i = 0 ; i < MAX (n_row, n_col) ; i++){ASSERT (Wp [i] < 0) ;}}DEBUG4 (("max_cdeg: "ID"\n", max_cdeg)) ;#endifASSERT (pivcol [OUT] >= 0 && pivcol [OUT] < n_col) ;ASSERT (NON_PIVOTAL_COL (pivcol [OUT])) ;tpi = Col_tuples [pivcol [OUT]] ;if (tpi){tp = (Tuple *) (Memory + tpi) ;tp1 = tp ;tp2 = tp ;tpend = tp + Col_tlen [pivcol [OUT]] ;for ( ; tp < tpend ; tp++){e = tp->e ;ASSERT (e > 0 && e <= Work->nel) ;if (!E [e]) continue ; /* element already deallocated */f = tp->f ;p = Memory + E [e] ;ep = (Element *) p ;p += UNITS (Element, 1) ;Cols = (Int *) p ;if (Cols [f] == EMPTY) continue ; /* column already assembled */ASSERT (pivcol [OUT] == Cols [f]) ;Rows = Cols + ep->ncols ;nrows = ep->nrows ;p += UNITS (Int, ep->ncols + nrows) ;C = ((Entry *) p) + f * nrows ;for (i = 0 ; i < nrows ; i++){row = Rows [i] ;if (row >= 0) /* skip this if already gone from element */{ASSERT (row < n_row) ;pos = Wp [row] ;if (pos < 0){/* new entry in the pattern - save Wp */ASSERT (cdeg_out < n_row) ;if (cdeg_out >= max_cdeg){/* :: pattern change (cdeg out failure) :: */DEBUGm4 (("cdeg out failure\n")) ;return (UMFPACK_ERROR_different_pattern) ;}Wp [row] = cdeg_out ;Wm [cdeg_out] = row ;Wx [cdeg_out++] = C [i] ;}else{/* entry already in pattern - sum the values *//* Wx [pos] += C [i] ; */ASSEMBLE (Wx [pos], C [i]) ;}}}*tp2++ = *tp ; /* leave the tuple in the list */}Col_tlen [pivcol [OUT]] = tp2 - tp1 ;}/* ------------------------------------------------------------------ */#ifndef NDEBUGDEBUG4 (("Reduced column: cdeg out "ID"\n", cdeg_out)) ;for (i = 0 ; i < cdeg_out ; i++){DEBUG4 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ;EDEBUG4 (Wx [i]) ;DEBUG4 (("\n")) ;ASSERT (i == Wp [Wm [i]]) ;}#endif/* ------------------------------------------------------------------ *//* new degree of pivcol [OUT] is cdeg_out *//* ------------------------------------------------------------------ *//* search for two candidate pivot rows */status = UMF_row_search (Numeric, Work, Symbolic,0, cdeg_out, Wm, Wp, /* pattern of column to search */pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Wx,pivcol [OUT], freebie) ;/* ------------------------------------------------------------------ *//* fatal error if matrix pattern has changed since symbolic analysis *//* ------------------------------------------------------------------ */if (status == UMFPACK_ERROR_different_pattern){/* :: pattern change detected in umf_local_search :: */return (UMFPACK_ERROR_different_pattern) ;}/* ------------------------------------------------------------------ *//* Clear Wp *//* ------------------------------------------------------------------ */for (i = 0 ; i < cdeg_out ; i++){Wp [Wm [i]] = EMPTY ; /* clear Wp */}/* ------------------------------------------------------------------ *//* check for rectangular, singular matrix *//* ------------------------------------------------------------------ */if (status == UMFPACK_WARNING_singular_matrix){/* Pivot column is empty, and row-merge set is empty too. The* matrix is structurally singular. The current frontal matrix must* be empty, too. It it weren't, and pivcol [OUT] exists, then* there would be at least one row that could be selected. Since* the current front is empty, pivcol [IN] must also be EMPTY.*/DEBUGm4 (("Note: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ;ASSERT ((Work->fnrows == 0 && Work->fncols == 0)) ;ASSERT (pivcol [IN] == EMPTY) ;/* remove the failed pivcol [OUT] from candidate set */ASSERT (pivcol [OUT] == Work->Candidates [jcand [OUT]]) ;remove_candidate (jcand [OUT], Work, Symbolic) ;Work->ndiscard++ ;/* delete all of the tuples, and all contributions to this column */DEBUG1 (("Prune tuples of dead outcol: "ID"\n", pivcol [OUT])) ;Col_tlen [pivcol [OUT]] = 0 ;UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol [OUT]]) ;Col_tuples [pivcol [OUT]] = 0 ;/* no pivot found at all */return (UMFPACK_WARNING_singular_matrix) ;}/* ------------------------------------------------------------------ */if (freebie [IN]){/* the "in" row is the same as the "in" row for the "in" column */Woi = Fcols ;rdeg [OUT][IN] = rdeg [IN][IN] ;DEBUG4 (("Freebie in, row "ID"\n", pivrow [IN][IN])) ;}if (freebie [OUT]){/* the "out" row is the same as the "out" row for the "in" column */Woo = Wio ;rdeg [OUT][OUT] = rdeg [IN][OUT] ;DEBUG4 (("Freebie out, row "ID"\n", pivrow [IN][OUT])) ;}/* ------------------------------------------------------------------ *//* evaluate OUT_IN option *//* ------------------------------------------------------------------ */if (pivrow [OUT][IN] != EMPTY){/* The current front would become an Lson of the new front.* The candidate pivot row is in the current front, but the* candidate pivot column is not. */ASSERT (fnrows > 0 && fncols >= 0) ;did_rowmerge = (cdeg_out == 0) ;if (did_rowmerge){/* pivrow [OUT][IN] was found via row merge search *//* it is not (yet) in the pivot column pattern (add it now) */DEBUGm4 (("did row merge OUT col, IN row\n")) ;Wm [0] = pivrow [OUT][IN] ;CLEAR (Wx [0]) ;cdeg_out = 1 ;ASSERT (nr_out == EMPTY) ;}nc = rdeg [OUT][IN] - fncols ;ASSERT (nc >= 1) ;/* count rows not in current front */nr_out = 0 ;#ifndef NDEBUGdebug_ok = FALSE ;#endiffor (i = 0 ; i < cdeg_out ; i++){row = Wm [i] ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;#ifndef NDEBUG/* we must see the pivot row somewhere */if (row == pivrow [OUT][IN]){ASSERT (Frpos [row] >= 0) ;debug_ok = TRUE ;}#endif}ASSERT (debug_ok) ;thiscost =/* each column in front grows by nr_out: */(nr_out * fncols) +/* new cols not affected by front: */((nc-1) * (cdeg_out-1)) ;/* check the cost of relaxed OUT_IN amalgamation */extra_rows = ((fnrows-1) + nr_out) - (cdeg_out - 1) ;ASSERT (extra_rows >= 0) ;ASSERT (fnrows + nr_out == extra_rows + cdeg_out) ;extra_zeros = (nc-1) * extra_rows ; /* symbolic fill-in */ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;ASSERT (fncols + nc == rdeg [OUT][IN]) ;/* size of relaxed front (after pivot row removed): */fnrows_new [OUT][IN] = (fnrows-1) + nr_out ;fncols_new [OUT][IN] = fncols + (nc-1) ;relaxed_front = fnrows_new [OUT][IN] * fncols_new [OUT][IN] ;/* do relaxed amalgamation if the extra zeros are no more *//* than a fraction (default 0.25) of the relaxed front *//* if relax = 0: no extra zeros allowed *//* if relax = +inf: always amalgamate */if (did_rowmerge){do_extend = FALSE ;}else{/* relax parameter uses a double relop, but ignore NaN case: */if (extra_zeros == 0){do_extend = TRUE ;}else{do_extend = ((double) extra_zeros) <(relax1 * (double) relaxed_front) ;}}if (do_extend){/* count the cost of relaxed amalgamation */thiscost += extra_zeros ;DEBUG2 (("Evaluating option OUT-IN:\n")) ;DEBUG2 ((" Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",Work->fnzeros, fnpiv, nr_out, nc)) ;DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;/* determine if BLAS-3 update to be applied before extending. *//* update if too many zero entries accumulate in the LU block */fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;/* RELAX3 parameter uses a double relop, ignore NaN case: */do_update = fnpiv > 0 &&(((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;DEBUG2 (("do_update "ID"\n", do_update))}else{/* the current front would not be extended */do_update = fnpiv > 0 ;fnzeros = 0 ;DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update)) ;/* The new front would be just big enough to hold the new* pivot row and column. */fnrows_new [OUT][IN] = cdeg_out - 1 ;fncols_new [OUT][IN] = rdeg [OUT][IN] - 1 ;}DEBUG2 (("option OUT IN : nr "ID" nc "ID" cost "ID"("ID") relax "ID"\n", nr_out, nc, thiscost, extra_zeros, do_extend)) ;if (bestcost == EMPTY || thiscost < bestcost){/* this is the best option seen so far */Work->pivot_case = OUT_IN ;bestcost = thiscost ;Work->do_extend = do_extend ;Work->do_update = do_update ;new_fnzeros = fnzeros ;}}/* ------------------------------------------------------------------ *//* evaluate OUT_OUT option *//* ------------------------------------------------------------------ */if (pivrow [OUT][OUT] != EMPTY){/* Neither the candidate pivot row nor the candidate pivot column* are in the current front. */ASSERT (fnrows >= 0 && fncols >= 0) ;did_rowmerge = (cdeg_out == 0) ;if (did_rowmerge){/* pivrow [OUT][OUT] was found via row merge search *//* it is not (yet) in the pivot column pattern (add it now) */DEBUGm4 (("did row merge OUT col, OUT row\n")) ;Wm [0] = pivrow [OUT][OUT] ;CLEAR (Wx [0]) ;cdeg_out = 1 ;ASSERT (nr_out == EMPTY) ;nr_out = 1 ;}if (fnrows == 0 && fncols == 0){/* the current front is completely empty */ASSERT (fnpiv == 0) ;nc = rdeg [OUT][OUT] ;extra_cols = 0 ;nr_out = cdeg_out ;extra_rows = 0 ;extra_zeros = 0 ;thiscost = (nc-1) * (cdeg_out-1) ; /* new columns only *//* size of new front: */fnrows_new [OUT][OUT] = nr_out-1 ;fncols_new [OUT][OUT] = nc-1 ;relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;}else{/* count rows not in current front */if (nr_out == EMPTY){nr_out = 0 ;#ifndef NDEBUGdebug_ok = FALSE ;#endiffor (i = 0 ; i < cdeg_out ; i++){row = Wm [i] ;ASSERT (row >= 0 && row < n_row) ;ASSERT (NON_PIVOTAL_ROW (row)) ;if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;#ifndef NDEBUG/* we must see the pivot row somewhere */if (row == pivrow [OUT][OUT]){ASSERT (Frpos [row] < 0 || Frpos [row] >= fnrows) ;debug_ok = TRUE ;}#endif}ASSERT (debug_ok) ;}/* count columns not in current front */nc = 0 ;#ifndef NDEBUGdebug_ok = FALSE ;#endiffor (i = 0 ; i < rdeg [OUT][OUT] ; i++){col = Woo [i] ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;if (Fcpos [col] < 0) nc++ ;#ifndef NDEBUG/* we must see the pivot column somewhere */if (col == pivcol [OUT]){ASSERT (Fcpos [col] < 0) ;debug_ok = TRUE ;}#endif}ASSERT (debug_ok) ;extra_cols = (fncols + (nc-1)) - (rdeg [OUT][OUT] - 1) ;extra_rows = (fnrows + (nr_out-1)) - (cdeg_out - 1) ;ASSERT (extra_rows >= 0) ;ASSERT (extra_cols >= 0) ;extra_zeros = ((nc-1) * extra_rows) + ((nr_out-1) * extra_cols);ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;ASSERT (fncols + nc == rdeg [OUT][OUT] + extra_cols) ;thiscost =/* new columns: */((nc-1) * (cdeg_out-1)) +/* old columns in front grow by nr_out-1: */((nr_out-1) * (fncols - extra_cols)) ;/* size of relaxed front: */fnrows_new [OUT][OUT] = fnrows + (nr_out-1) ;fncols_new [OUT][OUT] = fncols + (nc-1) ;relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;}/* do relaxed amalgamation if the extra zeros are no more *//* than a fraction (default 0.25) of the relaxed front *//* if relax = 0: no extra zeros allowed *//* if relax = +inf: always amalgamate */if (did_rowmerge){do_extend = FALSE ;}else{/* relax parameter uses a double relop, but ignore NaN case: */if (extra_zeros == 0){do_extend = TRUE ;}else{do_extend = ((double) extra_zeros) <(relax1 * (double) relaxed_front) ;}}if (do_extend){/* count the cost of relaxed amalgamation */thiscost += extra_zeros ;DEBUG2 (("Evaluating option OUT-OUT:\n")) ;DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",Work->fnzeros, fnpiv, nr_out, nc)) ;DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;/* determine if BLAS-3 update to be applied before extending. *//* update if too many zero entries accumulate in the LU block */fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;/* RELAX3 parameter uses a double relop, ignore NaN case: */do_update = fnpiv > 0 &&(((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;DEBUG2 (("do_update "ID"\n", do_update))}else{/* the current front would not be extended */do_update = fnpiv > 0 ;fnzeros = 0 ;DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update)) ;/* The new front would be just big enough to hold the new* pivot row and column. */fnrows_new [OUT][OUT] = cdeg_out - 1 ;fncols_new [OUT][OUT] = rdeg [OUT][OUT] - 1 ;}DEBUG2 (("option OUT OUT: nr "ID" nc "ID" cost "ID"\n",rdeg [OUT][OUT], cdeg_out, thiscost)) ;if (bestcost == EMPTY || thiscost < bestcost){/* this is the best option seen so far */Work->pivot_case = OUT_OUT ;bestcost = thiscost ;Work->do_extend = do_extend ;Work->do_update = do_update ;new_fnzeros = fnzeros ;}}}/* At this point, a structural pivot has been found. *//* It may be numerically zero, however. */ASSERT (Work->pivot_case != EMPTY) ;DEBUG2 (("local search, best option "ID", best cost "ID"\n",Work->pivot_case, bestcost)) ;/* ====================================================================== *//* Pivot row and column, and extension, now determined *//* ====================================================================== */Work->fnzeros = new_fnzeros ;/* ---------------------------------------------------------------------- *//* finalize the pivot row and column *//* ---------------------------------------------------------------------- */switch (Work->pivot_case){case IN_IN:DEBUG2 (("IN-IN option selected\n")) ;ASSERT (fnrows > 0 && fncols > 0) ;Work->pivcol_in_front = TRUE ;Work->pivrow_in_front = TRUE ;Work->pivcol = pivcol [IN] ;Work->pivrow = pivrow [IN][IN] ;Work->ccdeg = nr_in ;Work->Wrow = Fcols ;Work->rrdeg = rdeg [IN][IN] ;jj = jcand [IN] ;Work->fnrows_new = fnrows_new [IN][IN] ;Work->fncols_new = fncols_new [IN][IN] ;break ;case IN_OUT:DEBUG2 (("IN-OUT option selected\n")) ;ASSERT (fnrows >= 0 && fncols > 0) ;Work->pivcol_in_front = TRUE ;Work->pivrow_in_front = FALSE ;Work->pivcol = pivcol [IN] ;Work->pivrow = pivrow [IN][OUT] ;Work->ccdeg = nr_in ;Work->Wrow = Wio ;Work->rrdeg = rdeg [IN][OUT] ;jj = jcand [IN] ;Work->fnrows_new = fnrows_new [IN][OUT] ;Work->fncols_new = fncols_new [IN][OUT] ;break ;case OUT_IN:DEBUG2 (("OUT-IN option selected\n")) ;ASSERT (fnrows > 0 && fncols >= 0) ;Work->pivcol_in_front = FALSE ;Work->pivrow_in_front = TRUE ;Work->pivcol = pivcol [OUT] ;Work->pivrow = pivrow [OUT][IN] ;Work->ccdeg = cdeg_out ;/* Wrow might be equivalenced to Fcols (Freebie in): */Work->Wrow = Woi ;Work->rrdeg = rdeg [OUT][IN] ;/* Work->Wrow[0..fncols-1] is not there. See Fcols instead */jj = jcand [OUT] ;Work->fnrows_new = fnrows_new [OUT][IN] ;Work->fncols_new = fncols_new [OUT][IN] ;break ;case OUT_OUT:DEBUG2 (("OUT-OUT option selected\n")) ;ASSERT (fnrows >= 0 && fncols >= 0) ;Work->pivcol_in_front = FALSE ;Work->pivrow_in_front = FALSE ;Work->pivcol = pivcol [OUT] ;Work->pivrow = pivrow [OUT][OUT] ;Work->ccdeg = cdeg_out ;/* Wrow might be equivalenced to Wio (Freebie out): */Work->Wrow = Woo ;Work->rrdeg = rdeg [OUT][OUT] ;jj = jcand [OUT] ;Work->fnrows_new = fnrows_new [OUT][OUT] ;Work->fncols_new = fncols_new [OUT][OUT] ;break ;}ASSERT (IMPLIES (fnrows == 0 && fncols == 0, Work->pivot_case == OUT_OUT)) ;if (!Work->pivcol_in_front && pivcol [IN] != EMPTY){/* clear Frpos if pivcol [IN] was searched, but not selected */for (i = fnrows ; i < cdeg_in ; i++){Frpos [Frows [i]] = EMPTY;}}/* ---------------------------------------------------------------------- *//* Pivot row and column have been found *//* ---------------------------------------------------------------------- *//* ---------------------------------------------------------------------- *//* remove pivot column from candidate pivot column set *//* ---------------------------------------------------------------------- */ASSERT (jj >= 0 && jj < Work->nCandidates) ;ASSERT (Work->pivcol == Work->Candidates [jj]) ;remove_candidate (jj, Work, Symbolic) ;/* ---------------------------------------------------------------------- *//* check for frontal matrix growth *//* ---------------------------------------------------------------------- */DEBUG1 (("Check frontal growth:\n")) ;DEBUG1 (("fnrows_new "ID" + 1 = "ID", fnr_curr "ID"\n",Work->fnrows_new, Work->fnrows_new + 1, fnr_curr)) ;DEBUG1 (("fncols_new "ID" + 1 = "ID", fnc_curr "ID"\n",Work->fncols_new, Work->fncols_new + 1, fnc_curr)) ;Work->do_grow = (Work->fnrows_new + 1 > fnr_curr|| Work->fncols_new + 1 > fnc_curr) ;if (Work->do_grow){DEBUG0 (("\nNeed to grow frontal matrix, force do_update true\n")) ;/* If the front must grow, then apply the pending updates and remove* the current pivot rows/columns from the front prior to growing the* front. This frees up as much space as possible for the new front. */if (!Work->do_update && fnpiv > 0){/* This update would not have to be done if the current front* was big enough. */Work->nforced++ ;Work->do_update = TRUE ;}}/* ---------------------------------------------------------------------- *//* current pivot column *//* ---------------------------------------------------------------------- *//*c1) If pivot column index is in the current front:The pivot column pattern is in Frows [0 .. fnrows-1] andthe extension is in Frows [fnrows ... fnrows+ccdeg-1].Frpos [Frows [0 .. fnrows+ccdeg-1]] isequal to 0 .. fnrows+ccdeg-1. Wm is not needed.The values are in Wy [0 .. fnrows+ccdeg-1].c2) Otherwise, if the pivot column index is not in the current front:c2a) If the front is being extended, old row indices in the thepivot column pattern are in Frows [0 .. fnrows-1].All entries are in Wm [0 ... ccdeg-1], with values inWx [0 .. ccdeg-1]. These may include entries already inFrows [0 .. fnrows-1].Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1.Frpos [Wm [0 .. ccdeg-1]] for new entries is < 0.c2b) If the front is not being extended, then the entire pivotcolumn pattern is in Wm [0 .. ccdeg-1]. It includesthe pivot row index. It is does not contain the patternFrows [0..fnrows-1]. The intersection of these twosets may or may not be empty. The values are in Wx [0..ccdeg-1]In both cases c1 and c2, Frpos [Frows [0 .. fnrows-1]] is equalto 0 .. fnrows-1, which is the pattern of the current front.Any entry of Frpos that is not specified above is < 0.*/#ifndef NDEBUGDEBUG2 (("\n\nSEARCH DONE: Pivot col "ID" in: ("ID") pivot row "ID" in: ("ID") extend: "ID"\n\n", Work->pivcol, Work->pivcol_in_front,Work->pivrow, Work->pivrow_in_front, Work->do_extend)) ;UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, !Symbolic->fixQ) ;DEBUG2 (("Pivot col "ID": fnrows "ID" ccdeg "ID"\n", Work->pivcol, fnrows,Work->ccdeg)) ;if (Work->pivcol_in_front) /* case c1 */{Int found = FALSE ;DEBUG3 (("Pivcol in front\n")) ;for (i = 0 ; i < fnrows ; i++){row = Frows [i] ;DEBUG3 ((ID": row:: "ID" in front ", i, row)) ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;ASSERT (Frpos [row] == i) ;EDEBUG3 (Wy [i]) ;if (row == Work->pivrow){DEBUG3 ((" <- pivrow")) ;found = TRUE ;}DEBUG3 (("\n")) ;}ASSERT (found == Work->pivrow_in_front) ;found = FALSE ;for (i = fnrows ; i < fnrows + Work->ccdeg ; i++){row = Frows [i] ;DEBUG3 ((ID": row:: "ID" (new)", i, row)) ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;ASSERT (Frpos [row] == i) ;EDEBUG3 (Wy [i]) ;if (row == Work->pivrow){DEBUG3 ((" <- pivrow")) ;found = TRUE ;}DEBUG3 (("\n")) ;}ASSERT (found == !Work->pivrow_in_front) ;}else{if (Work->do_extend){Int found = FALSE ;DEBUG3 (("Pivcol not in front (extend)\n")) ;for (i = 0 ; i < fnrows ; i++){row = Frows [i] ;DEBUG3 ((ID": row:: "ID" in front ", i, row)) ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;ASSERT (Frpos [row] == i) ;if (row == Work->pivrow){DEBUG3 ((" <- pivrow")) ;found = TRUE ;}DEBUG3 (("\n")) ;}ASSERT (found == Work->pivrow_in_front) ;found = FALSE ;DEBUG3 (("----\n")) ;for (i = 0 ; i < Work->ccdeg ; i++){row = Wm [i] ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;DEBUG3 ((ID": row:: "ID" ", i, row)) ;EDEBUG3 (Wx [i]) ;if (Frpos [row] < 0){DEBUG3 ((" (new) ")) ;}if (row == Work->pivrow){DEBUG3 ((" <- pivrow")) ;found = TRUE ;/* ... */if (Work->pivrow_in_front) ASSERT (Frpos [row] >= 0) ;else ASSERT (Frpos [row] < 0) ;}DEBUG3 (("\n")) ;}ASSERT (found) ;}else{Int found = FALSE ;DEBUG3 (("Pivcol not in front (no extend)\n")) ;for (i = 0 ; i < Work->ccdeg ; i++){row = Wm [i] ;ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;DEBUG3 ((ID": row:: "ID" ", i, row)) ;EDEBUG3 (Wx [i]) ;DEBUG3 ((" (new) ")) ;if (row == Work->pivrow){DEBUG3 ((" <- pivrow")) ;found = TRUE ;}DEBUG3 (("\n")) ;}ASSERT (found) ;}}#endif/* ---------------------------------------------------------------------- *//* current pivot row *//* ---------------------------------------------------------------------- *//*r1) If the pivot row index is in the current front:The pivot row pattern is in Fcols [0..fncols-1] and the extenson isin Wrow [fncols .. rrdeg-1]. If the pivot column is in the currentfront, then Fcols and Wrow are equivalenced.r2) If the pivot row index is not in the current front:r2a) If the front is being extended, the pivot row pattern is inFcols [0 .. fncols-1]. New entries are in Wrow [0 .. rrdeg-1],but these may include entries already in Fcols [0 .. fncols-1].r2b) Otherwise, the pivot row pattern is Wrow [0 .. rrdeg-1].Fcpos [Fcols [0..fncols-1]] is (0..fncols-1) * fnr_curr.All other entries in Fcpos are < 0.These conditions are asserted below.------------------------------------------------------------------------Other items in Work structure that are relevant:pivcol: the pivot column indexpivrow: the pivot column indexrrdeg:ccdeg:fnrows: the number of rows in the currnt contribution blockfncols: the number of columns in the current contribution blockfnrows_new: the number of rows in the new contribution blockfncols_new: the number of rows in the new contribution block------------------------------------------------------------------------*/#ifndef NDEBUGUMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ;DEBUG2 (("Pivot row "ID":\n", Work->pivrow)) ;if (Work->pivrow_in_front){Int found = FALSE ;for (i = 0 ; i < fncols ; i++){col = Fcols [i] ;DEBUG3 ((" col:: "ID" in front\n", col)) ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;ASSERT (Fcpos [col] == i * fnr_curr) ;if (col == Work->pivcol) found = TRUE ;}ASSERT (found == Work->pivcol_in_front) ;found = FALSE ;ASSERT (IMPLIES (Work->pivcol_in_front, Fcols == Work->Wrow)) ;for (i = fncols ; i < Work->rrdeg ; i++){col = Work->Wrow [i] ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;ASSERT (Fcpos [col] < 0) ;if (col == Work->pivcol) found = TRUE ;else DEBUG3 ((" col:: "ID" (new)\n", col)) ;}ASSERT (found == !Work->pivcol_in_front) ;}else{if (Work->do_extend){Int found = FALSE ;for (i = 0 ; i < fncols ; i++){col = Fcols [i] ;DEBUG3 ((" col:: "ID" in front\n", col)) ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;ASSERT (Fcpos [col] == i * fnr_curr) ;if (col == Work->pivcol) found = TRUE ;}ASSERT (found == Work->pivcol_in_front) ;found = FALSE ;for (i = 0 ; i < Work->rrdeg ; i++){col = Work->Wrow [i] ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;if (Fcpos [col] >= 0) continue ;if (col == Work->pivcol) found = TRUE ;else DEBUG3 ((" col:: "ID" (new, extend)\n", col)) ;}ASSERT (found == !Work->pivcol_in_front) ;}else{Int found = FALSE ;for (i = 0 ; i < Work->rrdeg ; i++){col = Work->Wrow [i] ;ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;if (col == Work->pivcol) found = TRUE ;else DEBUG3 ((" col:: "ID" (all new)\n", col)) ;}ASSERT (found) ;}}#endif/* ---------------------------------------------------------------------- *//* determine whether to do scan2-row and scan2-col *//* ---------------------------------------------------------------------- */if (Work->do_extend){Work->do_scan2row = (fncols > 0) ;Work->do_scan2col = (fnrows > 0) ;}else{Work->do_scan2row = (fncols > 0) && Work->pivrow_in_front ;Work->do_scan2col = (fnrows > 0) && Work->pivcol_in_front ;}/* ---------------------------------------------------------------------- */DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID"\n",Work->pivcol, Work->pivrow)) ;DEBUG2 (("do_extend: "ID"\n", Work->do_extend)) ;DEBUG2 (("do_update: "ID"\n", Work->do_update)) ;DEBUG2 (("do_grow: "ID"\n", Work->do_grow)) ;/* ---------------------------------------------------------------------- *//* keep track of the diagonal *//* ---------------------------------------------------------------------- */if (Symbolic->prefer_diagonal&& Work->pivcol < Work->n_col - Symbolic->nempty_col){Diagonal_map = Work->Diagonal_map ;Diagonal_imap = Work->Diagonal_imap ;ASSERT (Diagonal_map != (Int *) NULL) ;ASSERT (Diagonal_imap != (Int *) NULL) ;row2 = Diagonal_map [Work->pivcol] ;col2 = Diagonal_imap [Work->pivrow] ;if (row2 < 0){/* this was an off-diagonal pivot row */Work->noff_diagonal++ ;row2 = UNFLIP (row2) ;}ASSERT (Diagonal_imap [row2] == Work->pivcol) ;ASSERT (UNFLIP (Diagonal_map [col2]) == Work->pivrow) ;if (row2 != Work->pivrow){/* swap the diagonal map to attempt to maintain symmetry later on.* Also mark the map for col2 (via FLIP) to denote that the entry* now on the diagonal is not the original entry on the diagonal. */DEBUG0 (("Unsymmetric pivot\n")) ;Diagonal_map [Work->pivcol] = FLIP (Work->pivrow) ;Diagonal_imap [Work->pivrow] = Work->pivcol ;Diagonal_map [col2] = FLIP (row2) ;Diagonal_imap [row2] = col2 ;}ASSERT (n_row == n_col) ;#ifndef NDEBUGUMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, Symbolic->n1,Symbolic->n_col, Symbolic->nempty_col) ;#endif}return (UMFPACK_OK) ;}