From 0c798c2b95a2c2d78a1eb54d0f8e8edd7e08a61e Mon Sep 17 00:00:00 2001 From: Lukas Schork Date: Sun, 12 May 2019 18:06:10 +0100 Subject: [PATCH 1/2] Implement basiclu_factorize_buckets(). basiclu_factorize() now calls basiclu_factorize_buckets() with argument buckets = NULL. Writing a separate interface for factorization with buckets was necessary to maintain the old API. The implementation has only been tested through test_factorize() in Julia. In particular rank deficient matrices have not been tested. --- Julia/basiclu.jl | 18 ++- Julia/test.jl | 18 ++- doc/userguide.pdf | Bin 150271 -> 153050 bytes doc/userguide.tex | 12 ++ include/basiclu.h | 3 + include/basiclu_factorize_buckets.h | 69 ++++++++++++ include/basiclu_obj_factorize.h | 8 +- include/basiclu_obj_factorize_buckets.h | 35 ++++++ src/basiclu_factorize.c | 118 +------------------ src/basiclu_factorize_buckets.c | 144 ++++++++++++++++++++++++ src/basiclu_object.c | 33 ++++-- src/lu_factorize_bump.c | 30 +++++ src/lu_internal.c | 7 ++ src/lu_internal.h | 5 +- src/lu_list.h | 20 ++++ src/lu_markowitz.c | 2 +- src/lu_pivot.c | 28 ++--- src/lu_setup_bump.c | 6 +- src/lu_singletons.c | 63 +++++++++-- 19 files changed, 453 insertions(+), 166 deletions(-) create mode 100644 include/basiclu_factorize_buckets.h create mode 100644 include/basiclu_obj_factorize_buckets.h create mode 100644 src/basiclu_factorize_buckets.c diff --git a/Julia/basiclu.jl b/Julia/basiclu.jl index 2715b3c..f15fb02 100644 --- a/Julia/basiclu.jl +++ b/Julia/basiclu.jl @@ -94,6 +94,7 @@ const BASICLU_MATRIX_INFNORM = 100 const BASICLU_RESIDUAL_TEST = 112 const BASICLU_MATRIX_NZ = 101 +const BASICLU_NBUCKETS = 113 const BASICLU_RANK = 102 const BASICLU_BUMP_SIZE = 103 const BASICLU_BUMP_NZ = 104 @@ -223,31 +224,36 @@ end # factorize # ============================================================================= """ - factorize(this, B) + factorize(this, B, buckets=C_NULL) Load sparse matrix into BASICLU object and factorize it. @B must be square -and have the same dimension for which @this was initialized. +and have the same dimension for which @this was initialized. If @buckets is +not C_NULL, then it must be of type Array{cint,1} and of length size(B,2). Return status code. """ -function factorize(this::BLU, B::spmatrix) +function factorize(this::BLU, B::spmatrix, buckets=C_NULL) m = convert(cint, this.xstore[BASICLU_DIM]) nrow, ncol = size(B) @assert nrow == ncol @assert nrow == m + if buckets != C_NULL + @assert typeof(buckets) == Array{cint,1} + @assert length(buckets) == m + end Bp = B.colptr-1 Bi = B.rowval-1 Bx = B.nzval # don't need a copy c0ntinue = 0 err = BASICLU_OK while true - err = ccall((:basiclu_factorize, "libbasiclu.so"), cint, + err = ccall((:basiclu_factorize_buckets, "libbasiclu.so"), cint, (cint_ptr, cdbl_ptr, cint_ptr, cdbl_ptr, cint_ptr, cdbl_ptr, cint_ptr, cdbl_ptr, - cint_ptr, cint_ptr, cint_ptr, cdbl_ptr, cint), + cint_ptr, cint_ptr, cint_ptr, cdbl_ptr, cint_ptr, cint), this.istore, this.xstore, this.Li, this.Lx, this.Ui, this.Ux, this.Wi, this.Wx, - Bp, pointer(Bp, 2), Bi, Bx, c0ntinue) + Bp, pointer(Bp, 2), Bi, Bx, buckets, c0ntinue) if err != BASICLU_REALLOCATE break; end realloc(this) c0ntinue = 1 diff --git a/Julia/test.jl b/Julia/test.jl index 0cf0c08..d61c973 100644 --- a/Julia/test.jl +++ b/Julia/test.jl @@ -19,14 +19,18 @@ end # test_factorize # ============================================================================= """ - test_factorize(testdir, trans=false) + test_factorize(testdir, trans=false, nbuckets=0) For all *.mat files in @testdir read matrix B and factorize it. Monitor residual of factorization and forward/backward solves. @trans specifies if B or its transposed are factorized. +@nbuckets specifies the number of column buckets. + nbuckets <= 0: no buckets used + nbuckets >= m: each column in its own bucket + 1 <= nbuckets <= m-1: column j in bucket mod(j-1, nbuckets) """ -function test_factorize(testdir::String, trans=false) +function test_factorize(testdir::String, trans=false, nbuckets=0) files = readdir(testdir) for f in files if length(f) < 4 || f[end-3:end] != ".mat" @@ -39,8 +43,16 @@ function test_factorize(testdir::String, trans=false) (B,Bt) = (Bt,B) end m = size(B,1) + buckets = C_NULL + if nbuckets > 0 + buckets = Array{cint}(m) + nbuckets = convert(cint, min(nbuckets, m)) + for j = 1:m + buckets[j] = mod(j-1, nbuckets) + end + end blu = initialize(m) - err = factorize(blu, B) + err = factorize(blu, B, buckets) if err != BASICLU_OK @printf(" failed (%d)\n", err) continue diff --git a/doc/userguide.pdf b/doc/userguide.pdf index 72cb069ef1cd65cdb7b85c4a8f27f9e852ab4d21..1dbfe7440d49143ffbf52b809c27e0ef049ab9ee 100644 GIT binary patch delta 57222 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 BXIlUO delta 54640 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

hqxJJ_txza)7wj!f9sFN#g{e=y=KEe zn5Gw#bW4qh&q1#&(%*v#pc!< z2Zp9~(_-E%S(i2Ie|mH4jSahLy_I%!*r=tQuUR(_z~0zPo90_-Czs6Ew%@$qo=RUv;ixGdS*WQ57; zlHVcbglG9w#BvPYJw$n42kAe}q)XOra-+##)*Js|?KZ#JS+rS^&Hux|zhnaNA?^%6r44I%{AFMrOE@D;`GeI#o(*KFcSMxRfbllAf^TJboGFp96R((%W zy*_T}Iqcy8F}mtxg>(NP^MB_h97~fii4y`dHkU|K0wI4hH(d%ZQ)zl-ATcvH3NKe6 zTQMLrATeDEFH&!BbRaP^G$1e_QVK6gZf0*FF*7wFFd$M2FG)loTRbvBMlv`tK|w(| zH9|o*IWagjHAXiyH9GB`0oK|wh+LP0k2#qo1~Ide8$>(A0wlf*^t}QV{Z5A*crsJ_9esd#{QvdJ2J}bW_hDIj5T!=l%KeyZHgY zzW@kRfIt*lkHxHbB&Ng+gWRlNpNS(PAVMYIro|I6Cqkluh;8`wsW>VciFn<&f3RpG z62F|sL^IL#)!8BE*?Cc1Am)IFsTE@oLF=OVoFe*xmnXXg!(BHrelbulPz67T;1upx1ac)#sTi`&G9 zs&iOmh~)$49Wg?zvfNe{Pe1jFWbHD zlj|X`337ACYm)r_(dz+&5WOCXd9lDCTLy#58V&(S2sgwEWo~41baG{3m%3E~6bv*u NHZ(B`B_%~qMhb}U0h|B; diff --git a/doc/userguide.tex b/doc/userguide.tex index 9591940..c0a4ea0 100644 --- a/doc/userguide.tex +++ b/doc/userguide.tex @@ -95,6 +95,12 @@ \subsection{basiclu\_factorize} \input{basiclu_factorize} } +\newpage +\subsection{basiclu\_factorize\_buckets} +{\footnotesize +\input{basiclu_factorize_buckets} +} + \newpage \subsection{basiclu\_get\_factors} {\footnotesize @@ -154,6 +160,12 @@ \subsection{basiclu\_obj\_factorize} \input{basiclu_obj_factorize} } +\newpage +\subsection{basiclu\_obj\_factorize\_buckets} +{\footnotesize +\input{basiclu_obj_factorize_buckets} +} + \newpage \subsection{basiclu\_obj\_get\_factors} {\footnotesize diff --git a/include/basiclu.h b/include/basiclu.h index 9bc784e..146f865 100644 --- a/include/basiclu.h +++ b/include/basiclu.h @@ -111,6 +111,7 @@ typedef int64_t lu_int; #define BASICLU_RESIDUAL_TEST 111 #define BASICLU_MATRIX_NZ 100 +#define BASICLU_NBUCKETS 112 #define BASICLU_RANK 101 #define BASICLU_BUMP_SIZE 102 #define BASICLU_BUMP_NZ 103 @@ -130,6 +131,7 @@ typedef int64_t lu_int; #include "basiclu_initialize.h" #include "basiclu_factorize.h" +#include "basiclu_factorize_buckets.h" #include "basiclu_get_factors.h" #include "basiclu_solve_dense.h" #include "basiclu_solve_sparse.h" @@ -139,6 +141,7 @@ typedef int64_t lu_int; #include "basiclu_object.h" #include "basiclu_obj_initialize.h" #include "basiclu_obj_factorize.h" +#include "basiclu_obj_factorize_buckets.h" #include "basiclu_obj_get_factors.h" #include "basiclu_obj_solve_dense.h" #include "basiclu_obj_solve_sparse.h" diff --git a/include/basiclu_factorize_buckets.h b/include/basiclu_factorize_buckets.h new file mode 100644 index 0000000..b2967af --- /dev/null +++ b/include/basiclu_factorize_buckets.h @@ -0,0 +1,69 @@ +lu_int basiclu_factorize_buckets +( + lu_int istore[], + double xstore[], + lu_int Li[], + double Lx[], + lu_int Ui[], + double Ux[], + lu_int Wi[], + double Wx[], + const lu_int Bbegin[], + const lu_int Bend[], + const lu_int Bi[], + const double Bx[], + const lu_int *buckets, + lu_int c0ntinue +); + +/* +Purpose: + + Performs the same task as basiclu_factorize(), just that the column ordering + of the factorization is restricted to pivot on all columns in bucket 0, + before those in bucket 1, and so on. If buckets == NULL, then no restriction + is imposed and the function performs identically to basiclu_factorize(). + +Return: + + see basiclu_factorize(). + +Arguments: + + const lu_int *buckets + + buckets[j] holds the bucket to which column j belongs. Buckets are + numbered from 0 to m-1. All columns in bucket 0 are chosen as pivot + column before those in bucket 1, and so on. When a column does not + contain an eligible pivot element (by means of the absolute pivot + tolerance), then it is ordered last in the pivot sequence, outside its + bucket. When buckets == NULL, then the function performs identically to + basiclu_factorize(). + + for the remaining arguments see basiclu_factorize(). + +Parameters: + + xstore[BASICLU_SEARCH_ROWS] + + This parameter has no effect when buckets are given, in which case only + columns are searched for pivot elements. + + for the remaining parameters see basiclu_factorize(). + +Info: + + xstore[BASICLU_STATUS]: status code. + + BASICLU_ERROR_invalid_argument + + The matrix is invalid (a column has a negative number of entries, + a row index is out of range, or a column has duplicate entries) or + buckets is invalid (buckets[j] < 0 or buckets[j] >= m for some j). + + for the remaining status codes see basiclu_factorize(). + + xstore[BASICLU_NBUCKETS] number of (nonempty) buckets. 0 if buckets == NULL. + + for the remaining info fields see basiclu_factorize(). +*/ diff --git a/include/basiclu_obj_factorize.h b/include/basiclu_obj_factorize.h index 8852fc8..a2a710e 100644 --- a/include/basiclu_obj_factorize.h +++ b/include/basiclu_obj_factorize.h @@ -1,10 +1,10 @@ lu_int basiclu_obj_factorize ( struct basiclu_object *obj, - const lu_int *Bbegin, - const lu_int *Bend, - const lu_int *Bi, - const double *Bx + const lu_int Bbegin[], + const lu_int Bend[], + const lu_int Bi[], + const double Bx[] ); /* diff --git a/include/basiclu_obj_factorize_buckets.h b/include/basiclu_obj_factorize_buckets.h new file mode 100644 index 0000000..37a4002 --- /dev/null +++ b/include/basiclu_obj_factorize_buckets.h @@ -0,0 +1,35 @@ +lu_int basiclu_obj_factorize_buckets +( + struct basiclu_object *obj, + const lu_int Bbegin[], + const lu_int Bend[], + const lu_int Bi[], + const double Bx[], + const lu_int *buckets +); + +/* +Purpose: + + Call basiclu_factorize_buckets() on a BASICLU object. + +Return: + + BASICLU_ERROR_invalid_object + + obj is NULL or initialized to a null object. + + BASICLU_ERROR_out_of_memory + + reallocation failed because of insufficient memory. + + Other return codes are passed through from basiclu_factorize_buckets(). + +Arguments: + + struct basiclu_object *obj + + Pointer to an initialized BASICLU object. + + The other arguments are passed through to basiclu_factorize_buckets(). +*/ diff --git a/src/basiclu_factorize.c b/src/basiclu_factorize.c index 28a83af..ac202bb 100644 --- a/src/basiclu_factorize.c +++ b/src/basiclu_factorize.c @@ -6,7 +6,6 @@ */ #include "lu_internal.h" -#include "lu_timer.h" lu_int basiclu_factorize ( @@ -25,119 +24,6 @@ lu_int basiclu_factorize lu_int c0ntinue ) { - struct lu this; - lu_int status; - double tic[2], elapsed, factor_cost; - lu_tic(tic); - - status = lu_load(&this, istore, xstore, Li, Lx, Ui, Ux, Wi, Wx); - if (status != BASICLU_OK) - return status; - - if (! (Li && Lx && Ui && Ux && Wi && Wx && Bbegin && Bend && Bi && Bx)) - { - status = BASICLU_ERROR_argument_missing; - return lu_save(&this, istore, xstore, status); - } - if (!c0ntinue) - { - lu_reset(&this); - this.task = SINGLETONS; - } - - /* continue factorization */ - switch (this.task) - { - case SINGLETONS: goto singletons; - case SETUP_BUMP: goto setup_bump; - case FACTORIZE_BUMP: goto factorize_bump; - case BUILD_FACTORS: goto build_factors; - } - status = BASICLU_ERROR_invalid_call; - return lu_save(&this, istore, xstore, status); - - /* - * Each of the following four parts of the factorization calls a routine - * lu_do_something() which may request reallocation. In this case return - * to the caller immediately, keeping the entry point in this.task. - */ - -singletons: - this.task = SINGLETONS; - status = lu_singletons(&this, Bbegin, Bend, Bi, Bx); - if (status != BASICLU_OK) - goto return_to_caller; - -setup_bump: - this.task = SETUP_BUMP; - status = lu_setup_bump(&this, Bbegin, Bend, Bi, Bx); - if (status != BASICLU_OK) - goto return_to_caller; - -factorize_bump: - this.task = FACTORIZE_BUMP; - status = lu_factorize_bump(&this); - if (status != BASICLU_OK) - goto return_to_caller; - -build_factors: - this.task = BUILD_FACTORS; - status = lu_build_factors(&this); - if (status != BASICLU_OK) - goto return_to_caller; - - /* factorization successfully finished */ - this.task = NO_TASK; - this.nupdate = 0; /* make factorization valid */ - this.ftran_for_update = -1; - this.btran_for_update = -1; - this.nfactorize++; - - this.condestL = lu_condest(this.m, this.Lbegin, this.Lindex, this.Lvalue, - NULL, this.p, 0, this.work1, - &this.normL, &this.normestLinv); - this.condestU = lu_condest(this.m, this.Ubegin, this.Uindex, this.Uvalue, - this.row_pivot, this.p, 1, this.work1, - &this.normU, &this.normestUinv); - - /* measure numerical stability of the factorization */ - lu_residual_test(&this, Bbegin, Bend, Bi, Bx); - - /* - * factor_cost is a deterministic measure of the factorization cost. - * The parameters have been adjusted such that (on my computer) - * 1e-6 * factor_cost =~ time_factorize. - * - * update_cost measures the accumulated cost of updates/solves compared - * to the last factorization. It is computed from - * - * update_cost = update_cost_numer / update_cost_denom. - * - * update_cost_denom is fixed here. - * update_cost_numer is zero here and increased by solves/updates. - * - */ - factor_cost = - 0.04 * this.m + - 0.07 * this.matrix_nz + - 0.20 * this.bump_nz + - 0.20 * this.nsearch_pivot + - 0.008 * this.factor_flops; - - this.update_cost_denom = factor_cost * 250; - - #if 0 - elapsed = this.time_factorize + lu_toc(tic); - printf(" 1e-6 * factor_cost / time_factorize: %.2f\n", - 1e-6 * factor_cost / elapsed); - #endif - - if (this.rank < this.m) - status = BASICLU_WARNING_singular_matrix; - -return_to_caller: - elapsed = lu_toc(tic); - this.time_factorize += elapsed; - this.time_factorize_total += elapsed; - return lu_save(&this, istore, xstore, status); + return basiclu_factorize_buckets(istore, xstore, Li, Lx, Ui, Ux, Wi, Wx, + Bbegin, Bend, Bi, Bx, NULL, c0ntinue); } diff --git a/src/basiclu_factorize_buckets.c b/src/basiclu_factorize_buckets.c new file mode 100644 index 0000000..716d08b --- /dev/null +++ b/src/basiclu_factorize_buckets.c @@ -0,0 +1,144 @@ +/* + * basiclu_factorize_buckets.c + * + * Copyright (C) 2016-2019 ERGO-Code + * + */ + +#include "lu_internal.h" +#include "lu_timer.h" + +lu_int basiclu_factorize_buckets +( + lu_int istore[], + double xstore[], + lu_int Li[], + double Lx[], + lu_int Ui[], + double Ux[], + lu_int Wi[], + double Wx[], + const lu_int Bbegin[], + const lu_int Bend[], + const lu_int Bi[], + const double Bx[], + const lu_int *buckets, + lu_int c0ntinue +) +{ + struct lu this; + lu_int status; + double tic[2], elapsed, factor_cost; + lu_tic(tic); + + status = lu_load(&this, istore, xstore, Li, Lx, Ui, Ux, Wi, Wx); + if (status != BASICLU_OK) + return status; + + if (! (Li && Lx && Ui && Ux && Wi && Wx && Bbegin && Bend && Bi && Bx)) + { + status = BASICLU_ERROR_argument_missing; + return lu_save(&this, istore, xstore, status); + } + if (!c0ntinue) + { + lu_reset(&this); + this.task = SINGLETONS; + } + + /* continue factorization */ + switch (this.task) + { + case SINGLETONS: goto singletons; + case SETUP_BUMP: goto setup_bump; + case FACTORIZE_BUMP: goto factorize_bump; + case BUILD_FACTORS: goto build_factors; + } + status = BASICLU_ERROR_invalid_call; + return lu_save(&this, istore, xstore, status); + + /* + * Each of the following four parts of the factorization calls a routine + * lu_do_something() which may request reallocation. In this case return + * to the caller immediately, keeping the entry point in this.task. + */ + +singletons: + this.task = SINGLETONS; + status = lu_singletons(&this, Bbegin, Bend, Bi, Bx, buckets); + if (status != BASICLU_OK) + goto return_to_caller; + +setup_bump: + this.task = SETUP_BUMP; + status = lu_setup_bump(&this, Bbegin, Bend, Bi, Bx); + if (status != BASICLU_OK) + goto return_to_caller; + +factorize_bump: + this.task = FACTORIZE_BUMP; + status = lu_factorize_bump(&this); + if (status != BASICLU_OK) + goto return_to_caller; + +build_factors: + this.task = BUILD_FACTORS; + status = lu_build_factors(&this); + if (status != BASICLU_OK) + goto return_to_caller; + + /* factorization successfully finished */ + this.task = NO_TASK; + this.nupdate = 0; /* make factorization valid */ + this.ftran_for_update = -1; + this.btran_for_update = -1; + this.nfactorize++; + + this.condestL = lu_condest(this.m, this.Lbegin, this.Lindex, this.Lvalue, + NULL, this.p, 0, this.work1, + &this.normL, &this.normestLinv); + this.condestU = lu_condest(this.m, this.Ubegin, this.Uindex, this.Uvalue, + this.row_pivot, this.p, 1, this.work1, + &this.normU, &this.normestUinv); + + /* measure numerical stability of the factorization */ + lu_residual_test(&this, Bbegin, Bend, Bi, Bx); + + /* + * factor_cost is a deterministic measure of the factorization cost. + * The parameters have been adjusted such that (on my computer) + * 1e-6 * factor_cost =~ time_factorize. + * + * update_cost measures the accumulated cost of updates/solves compared + * to the last factorization. It is computed from + * + * update_cost = update_cost_numer / update_cost_denom. + * + * update_cost_denom is fixed here. + * update_cost_numer is zero here and increased by solves/updates. + * + */ + factor_cost = + 0.04 * this.m + + 0.07 * this.matrix_nz + + 0.20 * this.bump_nz + + 0.20 * this.nsearch_pivot + + 0.008 * this.factor_flops; + + this.update_cost_denom = factor_cost * 250; + + #if 0 + elapsed = this.time_factorize + lu_toc(tic); + printf(" 1e-6 * factor_cost / time_factorize: %.2f\n", + 1e-6 * factor_cost / elapsed); + #endif + + if (this.rank < this.m) + status = BASICLU_WARNING_singular_matrix; + +return_to_caller: + elapsed = lu_toc(tic); + this.time_factorize += elapsed; + this.time_factorize_total += elapsed; + return lu_save(&this, istore, xstore, status); +} diff --git a/src/basiclu_object.c b/src/basiclu_object.c index 505f022..e650ba2 100644 --- a/src/basiclu_object.c +++ b/src/basiclu_object.c @@ -1,7 +1,7 @@ /* * basiclu_object.c * - * Copyright (C) 2016-2018 ERGO-Code + * Copyright (C) 2016-2019 ERGO-Code * */ @@ -200,27 +200,40 @@ void basiclu_obj_free(struct basiclu_object *obj) /* * basiclu_obj_factorize() */ -lu_int basiclu_obj_factorize(struct basiclu_object *obj, const lu_int *Bbegin, - const lu_int *Bend, const lu_int *Bi, - const double *Bx) +lu_int basiclu_obj_factorize(struct basiclu_object *obj, const lu_int Bbegin[], + const lu_int Bend[], const lu_int Bi[], + const double Bx[]) +{ + return basiclu_obj_factorize_buckets(obj, Bbegin, Bend, Bi, Bx, NULL); +} + +/* + * basiclu_obj_factorize_buckets() + */ +lu_int basiclu_obj_factorize_buckets(struct basiclu_object *obj, + const lu_int Bbegin[], const lu_int Bend[], + const lu_int Bi[], const double Bx[], + const lu_int *buckets) { lu_int status; if (!isvalid(obj)) return BASICLU_ERROR_invalid_object; - status = basiclu_factorize(obj->istore, obj->xstore, obj->Li, obj->Lx, - obj->Ui, obj->Ux, obj->Wi, obj->Wx, Bbegin, Bend, - Bi, Bx, 0); + status = basiclu_factorize_buckets(obj->istore, obj->xstore, + obj->Li, obj->Lx, obj->Ui, obj->Ux, + obj->Wi, obj->Wx, + Bbegin, Bend, Bi, Bx, buckets, 0); while (status == BASICLU_REALLOCATE) { status = lu_realloc_obj(obj); if (status != BASICLU_OK) break; - status = basiclu_factorize(obj->istore, obj->xstore, obj->Li, obj->Lx, - obj->Ui, obj->Ux, obj->Wi, obj->Wx, Bbegin, - Bend, Bi, Bx, 1); + status = basiclu_factorize_buckets(obj->istore, obj->xstore, + obj->Li, obj->Lx, obj->Ui, obj->Ux, + obj->Wi, obj->Wx, + Bbegin, Bend, Bi, Bx, buckets, 1); } return status; diff --git a/src/lu_factorize_bump.c b/src/lu_factorize_bump.c index 1c9e211..3740e96 100644 --- a/src/lu_factorize_bump.c +++ b/src/lu_factorize_bump.c @@ -10,6 +10,8 @@ #include "lu_internal.h" #include "lu_list.h" +static void lu_next_bucket(struct lu *this); + lu_int lu_factorize_bump(struct lu *this) { const lu_int m = this->m; @@ -21,6 +23,9 @@ lu_int lu_factorize_bump(struct lu *this) while (this->rank + this->rankdef < m) { + if (this->bucket_ptr == this->rank+this->rankdef+1) + lu_next_bucket(this); + /* * Find pivot element. Markowitz search need not be called if the * previous call to lu_pivot() returned for reallocation. In this case @@ -54,3 +59,28 @@ lu_int lu_factorize_bump(struct lu *this) } return status; } + +static void lu_next_bucket(struct lu *this) +{ + const lu_int m = this->m; + lu_int *colcount_flink = this->colcount_flink; + lu_int *colcount_blink = this->colcount_blink; + const lu_int *Wbegin = this->Wbegin; + const lu_int *Wend = this->Wend; + const lu_int *Lbegin_p = this->Lbegin_p; + lu_int bucket_ptr = this->bucket_ptr; + lu_int j, nz; + + assert(bucket_ptr >= 1 && bucket_ptr <= m); + assert(Lbegin_p[bucket_ptr] < 0); + + do { + j = Lbegin_p[bucket_ptr++]; + if (j < 0) j = -j-1; /* must unflip first index */ + assert(this->qinv[j] < 0); + nz = Wend[j] - Wbegin[j]; + lu_list_add(j, nz, colcount_flink, colcount_blink, m, &this->min_colnz); + } while (bucket_ptr <= m && Lbegin_p[bucket_ptr] >= 0); + + this->bucket_ptr = bucket_ptr; +} diff --git a/src/lu_internal.c b/src/lu_internal.c index 9aaa7d0..0d74d90 100644 --- a/src/lu_internal.c +++ b/src/lu_internal.c @@ -18,6 +18,7 @@ #define BASICLU_RANKDEF 261 #define BASICLU_MIN_COLNZ 262 #define BASICLU_MIN_ROWNZ 263 +#define BASICLU_BUCKET_PTR 264 #define BASICLU_MARKER 266 #define BASICLU_UPDATE_COST_NUMER 267 #define BASICLU_UPDATE_COST_DENOM 268 @@ -102,6 +103,7 @@ lu_int lu_load( this->residual_test = xstore[BASICLU_RESIDUAL_TEST]; this->matrix_nz = xstore[BASICLU_MATRIX_NZ]; + this->nbuckets = xstore[BASICLU_NBUCKETS]; this->rank = xstore[BASICLU_RANK]; this->bump_size = xstore[BASICLU_BUMP_SIZE]; this->bump_nz = xstore[BASICLU_BUMP_NZ]; @@ -126,6 +128,7 @@ lu_int lu_load( this->rankdef = xstore[BASICLU_RANKDEF]; this->min_colnz = xstore[BASICLU_MIN_COLNZ]; this->min_rownz = xstore[BASICLU_MIN_ROWNZ]; + this->bucket_ptr = xstore[BASICLU_BUCKET_PTR]; /* aliases to user arrays */ this->Lindex = Li; this->Lvalue = Lx; @@ -245,6 +248,7 @@ lu_int lu_save( xstore[BASICLU_RESIDUAL_TEST] = this->residual_test; xstore[BASICLU_MATRIX_NZ] = this->matrix_nz; + xstore[BASICLU_NBUCKETS] = this->nbuckets; xstore[BASICLU_RANK] = this->rank; xstore[BASICLU_BUMP_SIZE] = this->bump_size; xstore[BASICLU_BUMP_NZ] = this->bump_nz; @@ -269,6 +273,7 @@ lu_int lu_save( xstore[BASICLU_RANKDEF] = this->rankdef; xstore[BASICLU_MIN_COLNZ] = this->min_colnz; xstore[BASICLU_MIN_ROWNZ] = this->min_rownz; + xstore[BASICLU_BUCKET_PTR] = this->bucket_ptr; return status; } @@ -310,6 +315,7 @@ void lu_reset(struct lu *this) this->residual_test = 0; this->matrix_nz = 0; + this->nbuckets = 0; this->rank = 0; this->bump_size = 0; this->bump_nz = 0; @@ -334,6 +340,7 @@ void lu_reset(struct lu *this) this->rankdef = 0; this->min_colnz = 1; this->min_rownz = 1; + this->bucket_ptr = 0; /* * One past the final position in @Wend must hold the file size. diff --git a/src/lu_internal.h b/src/lu_internal.h index 46afb0d..b2485b8 100644 --- a/src/lu_internal.h +++ b/src/lu_internal.h @@ -74,6 +74,7 @@ struct lu double residual_test; /* computed by lu_residual_test() */ lu_int matrix_nz; /* nz in basis matrix when factorized */ + lu_int nbuckets; /* # column buckets; 0 if no buckets given */ lu_int rank; /* rank of basis matrix when factorized */ lu_int bump_size; lu_int bump_nz; @@ -99,6 +100,8 @@ struct lu because maximum was 0 or < abstol */ lu_int min_colnz; /* colcount lists 1..min_colnz-1 are empty */ lu_int min_rownz; /* rowcount lists 1..min_rownz-1 are empty */ + lu_int bucket_ptr; /* 1 <= bucket_ptr <= m is the beginning of the + next bucket in Lbegin_p; 0 if no buckets */ /* aliases to user arrays */ lu_int *Lindex, *Uindex, *Windex; @@ -170,7 +173,7 @@ lu_int lu_setup_bump( lu_int lu_singletons( struct lu *this, const lu_int *Bbegin, const lu_int *Bend, const lu_int *Bi, - const double *Bx); + const double *Bx, const lu_int *buckets); void lu_solve_dense( struct lu *this, const double *rhs, double *lhs, char trans); diff --git a/src/lu_list.h b/src/lu_list.h index 47329fc..468a586 100644 --- a/src/lu_list.h +++ b/src/lu_list.h @@ -37,6 +37,7 @@ * lu_list_add * lu_list_remove * lu_list_move + * lu_list_move_if * lu_list_swap * * The methods are defined in this header file as static inline. This header @@ -117,6 +118,25 @@ static inline void lu_list_move( } +/* ========================================================================== + * lu_list_move_if + * + * Remove element @elem from its list and add it to list @list. Do nothing if + * @elem is not in any list. + * ========================================================================== */ + +static inline void lu_list_move_if( + lu_int elem, lu_int list, lu_int *flink, lu_int *blink, lu_int nelem, + lu_int *min_list) +{ + if (flink[elem] != elem) + { + lu_list_remove(flink, blink, elem); + lu_list_add(elem, list, flink, blink, nelem, min_list); + } +} + + /* ========================================================================== * lu_list_swap * diff --git a/src/lu_markowitz.c b/src/lu_markowitz.c index 2f590aa..3c1c463 100644 --- a/src/lu_markowitz.c +++ b/src/lu_markowitz.c @@ -49,7 +49,7 @@ lu_int lu_markowitz(struct lu *this) const double abstol = this->abstol; const double reltol = this->reltol; const lu_int maxsearch = this->maxsearch; - const lu_int search_rows = this->search_rows; + const lu_int search_rows = this->search_rows && this->bucket_ptr==0; const lu_int nz_start = search_rows ? MIN(this->min_colnz, this->min_rownz) : this->min_colnz; diff --git a/src/lu_pivot.c b/src/lu_pivot.c index eb264f4..9e11262 100644 --- a/src/lu_pivot.c +++ b/src/lu_pivot.c @@ -333,10 +333,11 @@ static lu_int lu_pivot_any(struct lu *this) assert(Windex[Wbegin[j]] == pivot_row); Wbegin[j]++; - /* Move column to new list and update min_colnz. */ + /* Move column to new list and update min_colnz. If the column was not + in any list, then it belongs to another bucket and is kept out. */ nz = Wend[j] - Wbegin[j]; - lu_list_move(j, nz, colcount_flink, colcount_blink, m, - &this->min_colnz); + lu_list_move_if(j, nz, colcount_flink, colcount_blink, m, + &this->min_colnz); colmax[j] = cmx; } @@ -640,10 +641,11 @@ static lu_int lu_pivot_small(struct lu *this) assert(Windex[Wbegin[j]] == pivot_row); Wbegin[j]++; - /* Move column to new list and update min_colnz. */ + /* Move column to new list and update min_colnz. If the column was not + in any list, then it belongs to another bucket and is kept out. */ nz = Wend[j] - Wbegin[j]; - lu_list_move(j, nz, colcount_flink, colcount_blink, m, - &this->min_colnz); + lu_list_move_if(j, nz, colcount_flink, colcount_blink, m, + &this->min_colnz); colmax[j] = cmx; } @@ -911,8 +913,8 @@ static lu_int lu_pivot_singleton_col(struct lu *this) Windex[where] = Windex[--Wend [j]]; Wvalue[where] = Wvalue[Wend [j]]; nz = Wend[j] - Wbegin[j]; - lu_list_move(j, nz, colcount_flink, colcount_blink, m, - &this->min_colnz); + lu_list_move_if(j, nz, colcount_flink, colcount_blink, m, + &this->min_colnz); colmax[j] = cmx; } assert(found); @@ -1083,8 +1085,8 @@ static lu_int lu_pivot_doubleton_col(struct lu *this) /* Decrease column count. */ nz = end - Wbegin[j]; - lu_list_move(j, nz, colcount_flink, colcount_blink, m, - &this->min_colnz); + lu_list_move_if(j, nz, colcount_flink, colcount_blink, m, + &this->min_colnz); } } else @@ -1113,8 +1115,8 @@ static lu_int lu_pivot_doubleton_col(struct lu *this) /* Decrease column count. */ nz = Wend[j] - Wbegin[j]; - lu_list_move(j, nz, colcount_flink, colcount_blink, m, - &this->min_colnz); + lu_list_move_if(j, nz, colcount_flink, colcount_blink, m, + &this->min_colnz); } colmax[j] = cmx; } @@ -1247,5 +1249,5 @@ static void lu_remove_col(struct lu *this, lu_int j) /* Remove column j from column file. */ colmax[j] = 0.0; Wend[j] = cbeg; - lu_list_move(j, 0, colcount_flink, colcount_blink, m, &this->min_colnz); + lu_list_move_if(j, 0, colcount_flink, colcount_blink, m, &this->min_colnz); } diff --git a/src/lu_setup_bump.c b/src/lu_setup_bump.c index 55d2ee4..897ccca 100644 --- a/src/lu_setup_bump.c +++ b/src/lu_setup_bump.c @@ -63,6 +63,7 @@ lu_int lu_setup_bump( const double abstol = this->abstol; const lu_int pad = this->pad; const double stretch = this->stretch; + const lu_int have_buckets = this->bucket_ptr != 0; lu_int *colcount_flink = this->colcount_flink; lu_int *colcount_blink = this->colcount_blink; lu_int *rowcount_flink = this->rowcount_flink; @@ -129,14 +130,13 @@ lu_int lu_setup_bump( { /* Leave column of active submatrix empty. */ colmax[j] = 0.0; - lu_list_add(j, 0, colcount_flink, colcount_blink, m, &min_colnz); bump_nz -= cnz; + cnz = 0; } else { /* Copy column into active submatrix. */ colmax[j] = cmx; - lu_list_add(j, cnz, colcount_flink, colcount_blink, m, &min_colnz); Wbegin[j] = put; for (pos = Bbegin[j]; pos < Bend[j]; pos++) { @@ -152,6 +152,8 @@ lu_int lu_setup_bump( /* reappend line to list end */ lu_list_move(j, 0, Wflink, Wblink, 2*m, NULL); } + if (!have_buckets) + lu_list_add(j, cnz, colcount_flink, colcount_blink, m, &min_colnz); } /* diff --git a/src/lu_singletons.c b/src/lu_singletons.c index c6aae2b..bad5cbd 100644 --- a/src/lu_singletons.c +++ b/src/lu_singletons.c @@ -140,7 +140,7 @@ static lu_int singleton_rows lu_int lu_singletons( struct lu *this, const lu_int *Bbegin, const lu_int *Bend, const lu_int *Bi, - const double *Bx) + const double *Bx, const lu_int *buckets) { const lu_int m = this->m; const lu_int Lmem = this->Lmem; @@ -228,7 +228,7 @@ lu_int lu_singletons( i = Bi[pos]; put = iwork1[i]++; Bti[put] = j; - Btx[put] = Bx [pos]; + Btx[put] = Bx[pos]; if (put > Btp[i] && Bti[put-1] == j) ok = 0; } @@ -236,20 +236,66 @@ lu_int lu_singletons( if (!ok) return BASICLU_ERROR_invalid_argument; - /* ---------------- */ - /* Pivot singletons */ - /* ---------------- */ + /* If buckets are given, check that all of them are in range [0,m-1]. + * Then sort column indices 0..m-1 by order of nondecreasing bucket value + * in Lbegin_p[1..m]. Use qinv as workspace for bucket sort, taking O(m) + * time. If column index j is the first one in its bucket, store it flipped. + */ + if (buckets) + { + memset(qinv, 0, m*sizeof(lu_int)); + ok = 1; + for (j = 0; j < m; j++) + { + if (buckets[j] < 0 || buckets[j] >= m) + ok = 0; + else + qinv[buckets[j]]++; + } + if (!ok) + return BASICLU_ERROR_invalid_argument; + for (i = 0; i < m-1; i++) + qinv[i+1] += qinv[i]; + assert(qinv[m-1] == m); + for (j = 0; j < m; j++) + Lbegin_p[qinv[buckets[j]]--] = j; +#ifndef NDEBUG + for (pos = 2; pos <= m; pos++) + { + assert(buckets[Lbegin_p[pos]] >= buckets[Lbegin_p[pos-1]]); + } +#endif + this->nbuckets = 0; + for (pos = 1; pos <= m; pos++) + { + if (pos == 1 || buckets[Lbegin_p[pos]] != buckets[Lbegin_p[pos-1]]) + { + Lbegin_p[pos] = -Lbegin_p[pos]-1; + this->nbuckets++; + } + } + this->bucket_ptr = 1; + } /* No pivot rows or pivot columns so far. */ for (i = 0; i < m; i++) pinv[i] = -1; for (j = 0; j < m; j++) qinv[j] = -1; + Lbegin_p[0] = Ubegin[0] = 0; + this->matrix_nz = Bnz; + + /* If buckets are given, then do not eliminate singletons. */ + if (buckets) + return BASICLU_OK; + + /* ---------------- */ + /* Pivot singletons */ + /* ---------------- */ + rank = 0; if (nzbias >= 0) /* put more in U */ { - Lbegin_p[0] = Ubegin[0] = rank = 0; - rank = singleton_cols(m, Bbegin, Bend, Bi, Bx, Btp, Bti, Btx, Ubegin, Uindex, Uvalue, Lbegin_p, Lindex, Lvalue, col_pivot, pinv, qinv, iwork1, iwork2, rank, @@ -262,8 +308,6 @@ lu_int lu_singletons( } else /* put more in L */ { - Lbegin_p[0] = Ubegin[0] = rank = 0; - rank = singleton_rows(m, Bbegin, Bend, Bi, Bx, Btp, Bti, Btx, Ubegin, Uindex, Uvalue, Lbegin_p, Lindex, Lvalue, col_pivot, pinv, qinv, iwork1, iwork2, rank, @@ -283,7 +327,6 @@ lu_int lu_singletons( if (qinv[j] < 0) qinv[j] = -1; - this->matrix_nz = Bnz; this->rank = rank; this->time_singletons = lu_toc(tic); return BASICLU_OK; From 3d7342c392d7676bed2639491989dc182ed9e2dc Mon Sep 17 00:00:00 2001 From: Lukas Schork Date: Mon, 13 May 2019 09:05:04 +0100 Subject: [PATCH 2/2] Keep track of # active columns. Store # columns that are in any column list in struct lu.ncol_active. Terminate Markowitz search when # searched columns == # active columns. This is necessary to avoid traversing all column lists when only a few columns have been loaded into lists. For example, when the user provides a column permutation through the buckets argument, then in each factorization step only one column is loaded into the lists. --- src/lu_factorize_bump.c | 5 +++++ src/lu_internal.c | 4 ++++ src/lu_internal.h | 4 ++-- src/lu_markowitz.c | 16 +++++++++++----- src/lu_setup_bump.c | 4 ++++ 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/lu_factorize_bump.c b/src/lu_factorize_bump.c index 3740e96..1643866 100644 --- a/src/lu_factorize_bump.c +++ b/src/lu_factorize_bump.c @@ -25,6 +25,7 @@ lu_int lu_factorize_bump(struct lu *this) { if (this->bucket_ptr == this->rank+this->rankdef+1) lu_next_bucket(this); + assert(this->ncol_active > 0); /* * Find pivot element. Markowitz search need not be called if the @@ -41,6 +42,7 @@ lu_int lu_factorize_bump(struct lu *this) lu_list_remove(colcount_flink, colcount_blink, this->pivot_col); this->pivot_col = -1; this->rankdef++; + this->ncol_active--; } else { @@ -55,6 +57,7 @@ lu_int lu_factorize_bump(struct lu *this) this->pivot_col = -1; this->pivot_row = -1; this->rank++; + this->ncol_active--; } } return status; @@ -73,6 +76,7 @@ static void lu_next_bucket(struct lu *this) assert(bucket_ptr >= 1 && bucket_ptr <= m); assert(Lbegin_p[bucket_ptr] < 0); + assert(this->ncol_active == 0); do { j = Lbegin_p[bucket_ptr++]; @@ -80,6 +84,7 @@ static void lu_next_bucket(struct lu *this) assert(this->qinv[j] < 0); nz = Wend[j] - Wbegin[j]; lu_list_add(j, nz, colcount_flink, colcount_blink, m, &this->min_colnz); + this->ncol_active++; } while (bucket_ptr <= m && Lbegin_p[bucket_ptr] >= 0); this->bucket_ptr = bucket_ptr; diff --git a/src/lu_internal.c b/src/lu_internal.c index 0d74d90..a243363 100644 --- a/src/lu_internal.c +++ b/src/lu_internal.c @@ -19,6 +19,7 @@ #define BASICLU_MIN_COLNZ 262 #define BASICLU_MIN_ROWNZ 263 #define BASICLU_BUCKET_PTR 264 +#define BASICLU_NCOL_ACTIVE 265 #define BASICLU_MARKER 266 #define BASICLU_UPDATE_COST_NUMER 267 #define BASICLU_UPDATE_COST_DENOM 268 @@ -126,6 +127,7 @@ lu_int lu_load( this->marker = xstore[BASICLU_MARKER]; this->pivotlen = xstore[BASICLU_PIVOTLEN]; this->rankdef = xstore[BASICLU_RANKDEF]; + this->ncol_active = xstore[BASICLU_NCOL_ACTIVE]; this->min_colnz = xstore[BASICLU_MIN_COLNZ]; this->min_rownz = xstore[BASICLU_MIN_ROWNZ]; this->bucket_ptr = xstore[BASICLU_BUCKET_PTR]; @@ -271,6 +273,7 @@ lu_int lu_save( xstore[BASICLU_MARKER] = this->marker; xstore[BASICLU_PIVOTLEN] = this->pivotlen; xstore[BASICLU_RANKDEF] = this->rankdef; + xstore[BASICLU_NCOL_ACTIVE] = this->ncol_active; xstore[BASICLU_MIN_COLNZ] = this->min_colnz; xstore[BASICLU_MIN_ROWNZ] = this->min_rownz; xstore[BASICLU_BUCKET_PTR] = this->bucket_ptr; @@ -338,6 +341,7 @@ void lu_reset(struct lu *this) this->marker = 0; this->pivotlen = 0; this->rankdef = 0; + this->ncol_active = 0; this->min_colnz = 1; this->min_rownz = 1; this->bucket_ptr = 0; diff --git a/src/lu_internal.h b/src/lu_internal.h index b2485b8..cd23345 100644 --- a/src/lu_internal.h +++ b/src/lu_internal.h @@ -96,8 +96,8 @@ struct lu lu_int btran_for_update; /* >= 0 if BTRAN prepared for update */ lu_int marker; /* see @marked, below */ lu_int pivotlen; /* length of @pivotcol, @pivotrow; <= 2*m */ - lu_int rankdef; /* # columns removed from active submatrix - because maximum was 0 or < abstol */ + lu_int rankdef; /* # columns removed without pivot operation */ + lu_int ncol_active; /* # columns in lists */ lu_int min_colnz; /* colcount lists 1..min_colnz-1 are empty */ lu_int min_rownz; /* rowcount lists 1..min_rownz-1 are empty */ lu_int bucket_ptr; /* 1 <= bucket_ptr <= m is the beginning of the diff --git a/src/lu_markowitz.c b/src/lu_markowitz.c index 3c1c463..7a13f76 100644 --- a/src/lu_markowitz.c +++ b/src/lu_markowitz.c @@ -54,7 +54,7 @@ lu_int lu_markowitz(struct lu *this) MIN(this->min_colnz, this->min_rownz) : this->min_colnz; lu_int i, j, pos, where, inext, nz, pivot_row, pivot_col; - lu_int nsearch, cheap, found, min_colnz, min_rownz; + lu_int ncol_searched, nrow_searched, cheap, found, min_colnz, min_rownz; double cmx, x, tol, tic[2]; /* integers for Markowitz cost must be 64 bit to prevent overflow */ @@ -65,7 +65,8 @@ lu_int lu_markowitz(struct lu *this) pivot_row = -1; /* row of best pivot so far */ pivot_col = -1; /* col of best pivot so far */ MC = M*M; /* Markowitz cost of best pivot so far */ - nsearch = 0; /* count rows/columns searched */ + ncol_searched = 0; /* # columns searched for pivot */ + nrow_searched = 0; /* # rows searched for pivot */ min_colnz = -1; /* minimum col count in active submatrix */ min_rownz = -1; /* minimum row count in active submatrix */ assert(nz_start >= 1); @@ -82,9 +83,13 @@ lu_int lu_markowitz(struct lu *this) for (nz = nz_start; nz <= m; nz++) { + if (ncol_searched == this->ncol_active) + goto done; + /* Search columns with nz nonzeros. */ for (j = colcount_flink[m+nz]; j < m; j = colcount_flink[j]) { + ncol_searched++; if (min_colnz == -1) min_colnz = nz; assert(Wend[j] - Wbegin[j] == nz); @@ -115,7 +120,7 @@ lu_int lu_markowitz(struct lu *this) } /* We have seen at least one eligible pivot in column j. */ assert(MC < M*M); - if (++nsearch >= maxsearch) + if (ncol_searched+nrow_searched >= maxsearch) goto done; } assert(j == m+nz); @@ -126,6 +131,7 @@ lu_int lu_markowitz(struct lu *this) /* Search rows with nz nonzeros. */ for (i = rowcount_flink[m+nz]; i < m; i = inext) { + nrow_searched++; if (min_rownz == -1) min_rownz = nz; /* rowcount_flink[i] might be changed below, so keep a copy */ @@ -171,7 +177,7 @@ lu_int lu_markowitz(struct lu *this) else { assert(MC < M*M); - if (++nsearch >= maxsearch) + if (ncol_searched+nrow_searched >= maxsearch) goto done; } } @@ -181,7 +187,7 @@ lu_int lu_markowitz(struct lu *this) done: this->pivot_row = pivot_row; this->pivot_col = pivot_col; - this->nsearch_pivot += nsearch; + this->nsearch_pivot += ncol_searched+nrow_searched; if (min_colnz >= 0) this->min_colnz = min_colnz; if (min_rownz >= 0) diff --git a/src/lu_setup_bump.c b/src/lu_setup_bump.c index 897ccca..6b77e60 100644 --- a/src/lu_setup_bump.c +++ b/src/lu_setup_bump.c @@ -111,6 +111,7 @@ lu_int lu_setup_bump( * Build columnwise storage. Build row counts in iwork0. */ lu_list_init(colcount_flink, colcount_blink, m, m+2, &min_colnz); + this->ncol_active = 0; put = 0; for (j = 0; j < m; j++) { @@ -153,7 +154,10 @@ lu_int lu_setup_bump( lu_list_move(j, 0, Wflink, Wblink, 2*m, NULL); } if (!have_buckets) + { lu_list_add(j, cnz, colcount_flink, colcount_blink, m, &min_colnz); + this->ncol_active++; + } } /*