int inv_update(INV *inv, int j) { int m = inv->m; LUF *luf = inv->luf; int *vr_ptr = luf->vr_ptr; int *vr_len = luf->vr_len; int *vr_cap = luf->vr_cap; double *vr_piv = luf->vr_piv; int *vc_ptr = luf->vc_ptr; int *vc_len = luf->vc_len; int *vc_cap = luf->vc_cap; int *pp_row = luf->pp_row; int *pp_col = luf->pp_col; int *qq_row = luf->qq_row; int *qq_col = luf->qq_col; int *sv_ndx = luf->sv_ndx; double *sv_val = luf->sv_val; double *work = luf->work; double eps_tol = luf->eps_tol; int *hh_ndx = inv->hh_ndx; int *hh_ptr = inv->hh_ptr; int *hh_len = inv->hh_len; int cc_len = inv->cc_len; int *cc_ndx = inv->cc_ndx; double *cc_val = inv->cc_val; double upd_tol = inv->upd_tol; int ret = 0; int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q, p_beg, p_end, p_ptr, ptr; double f, temp; if (!inv->valid) fault("inv_update: the factorization is not valid"); if (inv->cc_len < 0) fault("inv_update: new column has not been prepared"); if (!(1 <= j && j <= m)) fault("inv_update: j = %d; invalid column number", j); /* check if a new factor of the matrix H can be created */ if (inv->hh_nfs == inv->hh_max) { /* maximal number of updates has been reached */ inv->valid = luf->valid = 0; ret = 3; goto done; } /* remove elements of the j-th column from the matrix V */ j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++) { /* get row index of v[i,j] */ i = sv_ndx[j_ptr]; /* find v[i,j] in the i-th row */ i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; sv_ndx[i_ptr] != j; i_ptr++) /* nop */; insist(i_ptr <= i_end); /* remove v[i,j] from the i-th row */ sv_ndx[i_ptr] = sv_ndx[i_end]; sv_val[i_ptr] = sv_val[i_end]; vr_len[i]--; } /* now the j-th column of the matrix V is empty */ luf->nnz_v -= vc_len[j]; vc_len[j] = 0; /* add elements of the new j-th column to the matrix V; determine indices k1 and k2 */ k1 = qq_row[j]; k2 = 0; for (ptr = 1; ptr <= cc_len; ptr++) { /* get row index of v[i,j] */ i = cc_ndx[ptr]; /* at least one unused location is needed in the i-th row */ if (vr_len[i] + 1 > vr_cap[i]) { if (luf_enlarge_row(luf, i, vr_len[i] + 10)) { /* overflow of the sparse vector area */ inv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; ret = 4; goto done; } } /* add v[i,j] to the i-th row */ i_ptr = vr_ptr[i] + vr_len[i]; sv_ndx[i_ptr] = j; sv_val[i_ptr] = cc_val[ptr]; vr_len[i]++; /* adjust the index k2 */ if (k2 < pp_col[i]) k2 = pp_col[i]; } /* capacity of the j-th column (which is currently empty) should be not less than cc_len locations */ if (vc_cap[j] < cc_len) { if (luf_enlarge_col(luf, j, cc_len)) { /* overflow of the sparse vector area */ inv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; ret = 4; goto done; } } /* add elements of the new j-th column to the column list */ j_ptr = vc_ptr[j]; memmove(&sv_ndx[j_ptr], &cc_ndx[1], cc_len * sizeof(int)); memmove(&sv_val[j_ptr], &cc_val[1], cc_len * sizeof(double)); vc_len[j] = cc_len; luf->nnz_v += cc_len; /* k1 > k2 means that the diagonal element u[k2,k2] is zero and therefore the adjacent basis matrix is structurally singular */ if (k1 > k2) { inv->valid = luf->valid = 0; ret = 1; goto done; } /* perform implicit symmetric permutations of rows and columns of the matrix U */ i = pp_row[k1], j = qq_col[k1]; for (k = k1; k < k2; k++) { pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k; qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k; } pp_row[k2] = i, pp_col[i] = k2; qq_col[k2] = j, qq_row[j] = k2; /* note that now the i-th row of the matrix V is the k2-th row of the matrix U; since no pivoting is used, only this row will be transformed */ /* copy elements of the i-th row of the matrix V to the working array and remove these elements from the matrix V */ for (j = 1; j <= m; j++) work[j] = 0.0; i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++) { /* get column index of v[i,j] */ j = sv_ndx[i_ptr]; /* store v[i,j] to the working array */ work[j] = sv_val[i_ptr]; /* find v[i,j] in the j-th column */ j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; sv_ndx[j_ptr] != i; j_ptr++) /* nop */; insist(j_ptr <= j_end); /* remove v[i,j] from the j-th column */ sv_ndx[j_ptr] = sv_ndx[j_end]; sv_val[j_ptr] = sv_val[j_end]; vc_len[j]--; } /* now the i-th row of the matrix V is empty */ luf->nnz_v -= vr_len[i]; vr_len[i] = 0; /* create the next row-like factor of the matrix H; this factor corresponds to the i-th (transformed) row */ inv->hh_nfs++; hh_ndx[inv->hh_nfs] = i; /* hh_ptr[] will be set later */ hh_len[inv->hh_nfs] = 0; /* up to (k2 - k1) free locations are needed to add new elements to the non-trivial row of the row-like factor */ if (luf->sv_end - luf->sv_beg < k2 - k1) { luf_defrag_sva(luf); if (luf->sv_end - luf->sv_beg < k2 - k1) { /* overflow of the sparse vector area */ inv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; ret = 4; goto done; } } /* eliminate subdiagonal elements of the matrix U */ for (k = k1; k < k2; k++) { /* v[p,q] = u[k,k] */ p = pp_row[k], q = qq_col[k]; /* this is the cruical point, where even tiny non-zeros should not be dropped */ if (work[q] == 0.0) continue; /* compute gaussian multiplier f = v[i,q] / v[p,q] */ f = work[q] / vr_piv[p]; /* perform gaussian transformation: (i-th row) := (i-th row) - f * (p-th row) in order to eliminate v[i,q] = u[k2,k] */ p_beg = vr_ptr[p]; p_end = p_beg + vr_len[p] - 1; for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++) work[sv_ndx[p_ptr]] -= f * sv_val[p_ptr]; /* store new element (gaussian multiplier that corresponds to the p-th row) in the current row-like factor */ luf->sv_end--; sv_ndx[luf->sv_end] = p; sv_val[luf->sv_end] = f; hh_len[inv->hh_nfs]++; } /* set pointer to the current row-like factor of the matrix H (if no elements were added to this factor, it is unity matrix and therefore can be discarded) */ if (hh_len[inv->hh_nfs] == 0) inv->hh_nfs--; else { hh_ptr[inv->hh_nfs] = luf->sv_end; inv->nnz_h += hh_len[inv->hh_nfs]; } /* store new pivot that corresponds to u[k2,k2] */ vr_piv[i] = work[qq_col[k2]]; #if 0 /* this naive check has been replaced by more appropriate check (see below) */ /* check if u[k2,k2] is close to zero */ if (fabs(vr_piv[i]) < upd_tol) { /* the factorization should be considered as inaccurate (this mainly happens due to excessive round-off errors) */ inv->valid = luf->valid = 0; ret = 2; goto done; } #endif /* new elements of the i-th row of the matrix V (which correspond to non-diagonal elements u[k2,k2+1], ..., u[k2,m] of the matrix U = P*V*Q) are contained in the working array; add them to the matrix V */ cc_len = 0; for (k = k2+1; k <= m; k++) { /* get column index and value of v[i,j] = u[k2,k] */ j = qq_col[k]; temp = work[j]; /* if v[i,j] is close to zero, skip it */ if (fabs(temp) < eps_tol) continue; /* at least one unused location is needed in the j-th column */ if (vc_len[j] + 1 > vc_cap[j]) { if (luf_enlarge_col(luf, j, vc_len[j] + 10)) { /* overflow of the sparse vector area */ inv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; ret = 4; goto done; } } /* add v[i,j] to the j-th column */ j_ptr = vc_ptr[j] + vc_len[j]; sv_ndx[j_ptr] = i; sv_val[j_ptr] = temp; vc_len[j]++; /* also store v[i,j] to the auxiliary array */ cc_len++; cc_ndx[cc_len] = j; cc_val[cc_len] = temp; } /* capacity of the i-th row (which is currently empty) should be not less than cc_len locations */ if (vr_cap[i] < cc_len) { if (luf_enlarge_row(luf, i, cc_len)) { /* overflow of the sparse vector area */ inv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; ret = 4; goto done; } } /* add new elements of the i-th row to the row list */ i_ptr = vr_ptr[i]; memmove(&sv_ndx[i_ptr], &cc_ndx[1], cc_len * sizeof(int)); memmove(&sv_val[i_ptr], &cc_val[1], cc_len * sizeof(double)); vr_len[i] = cc_len; luf->nnz_v += cc_len; #if 1 /* updating is finished; check that diagonal element u[k2,k2] is not very small in absolute value among other elements in k2-th row and k2-th column of the matrix U = P*V*Q */ /* temp = max(|u[k2,*]|, |u[*,k2]|) */ temp = 0.0; /* walk through k2-th row of U which is i-th row of V */ i = pp_row[k2]; i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++) if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]); /* walk through k2-th column of U which is j-th column of V */ j = qq_col[k2]; j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++) if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]); /* check that u[k2,k2] is not very small */ if (fabs(vr_piv[i]) < upd_tol * temp) { /* the factorization seems to be inaccurate and therefore must be recomputed */ inv->valid = luf->valid = 0; ret = 2; goto done; } #endif /* the factorization has been successfully updated */ inv->cc_len = -1; done: /* return to the simplex method routine */ return ret; }
int fhv_update_it(FHV *fhv, int j, int len, const int ind[], const double val[]) { int m = fhv->m; LUF *luf = fhv->luf; int *vr_ptr = luf->vr_ptr; int *vr_len = luf->vr_len; int *vr_cap = luf->vr_cap; double *vr_piv = luf->vr_piv; int *vc_ptr = luf->vc_ptr; int *vc_len = luf->vc_len; int *vc_cap = luf->vc_cap; int *pp_row = luf->pp_row; int *pp_col = luf->pp_col; int *qq_row = luf->qq_row; int *qq_col = luf->qq_col; int *sv_ind = luf->sv_ind; double *sv_val = luf->sv_val; double *work = luf->work; double eps_tol = luf->eps_tol; int *hh_ind = fhv->hh_ind; int *hh_ptr = fhv->hh_ptr; int *hh_len = fhv->hh_len; int *p0_row = fhv->p0_row; int *p0_col = fhv->p0_col; int *cc_ind = fhv->cc_ind; double *cc_val = fhv->cc_val; double upd_tol = fhv->upd_tol; int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q, p_beg, p_end, p_ptr, ptr, ret; double f, temp; if (!fhv->valid) xfault("fhv_update_it: the factorization is not valid\n"); if (!(1 <= j && j <= m)) xfault("fhv_update_it: j = %d; column number out of range\n", j); /* check if the new factor of matrix H can be created */ if (fhv->hh_nfs == fhv->hh_max) { /* maximal number of updates has been reached */ fhv->valid = 0; ret = FHV_ELIMIT; goto done; } /* convert new j-th column of B to dense format */ for (i = 1; i <= m; i++) cc_val[i] = 0.0; for (k = 1; k <= len; k++) { i = ind[k]; if (!(1 <= i && i <= m)) xfault("fhv_update_it: ind[%d] = %d; row number out of rang" "e\n", k, i); if (cc_val[i] != 0.0) xfault("fhv_update_it: ind[%d] = %d; duplicate row index no" "t allowed\n", k, i); if (val[k] == 0.0) xfault("fhv_update_it: val[%d] = %g; zero element not allow" "ed\n", k, val[k]); cc_val[i] = val[k]; } /* new j-th column of V := inv(F * H) * (new B[j]) */ fhv->luf->pp_row = p0_row; fhv->luf->pp_col = p0_col; luf_f_solve(fhv->luf, 0, cc_val); fhv->luf->pp_row = pp_row; fhv->luf->pp_col = pp_col; fhv_h_solve(fhv, 0, cc_val); /* convert new j-th column of V to sparse format */ len = 0; for (i = 1; i <= m; i++) { temp = cc_val[i]; if (temp == 0.0 || fabs(temp) < eps_tol) continue; len++, cc_ind[len] = i, cc_val[len] = temp; } /* clear old content of j-th column of matrix V */ j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++) { /* get row index of v[i,j] */ i = sv_ind[j_ptr]; /* find v[i,j] in the i-th row */ i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */; xassert(i_ptr <= i_end); /* remove v[i,j] from the i-th row */ sv_ind[i_ptr] = sv_ind[i_end]; sv_val[i_ptr] = sv_val[i_end]; vr_len[i]--; } /* now j-th column of matrix V is empty */ luf->nnz_v -= vc_len[j]; vc_len[j] = 0; /* add new elements of j-th column of matrix V to corresponding row lists; determine indices k1 and k2 */ k1 = qq_row[j], k2 = 0; for (ptr = 1; ptr <= len; ptr++) { /* get row index of v[i,j] */ i = cc_ind[ptr]; /* at least one unused location is needed in i-th row */ if (vr_len[i] + 1 > vr_cap[i]) { if (luf_enlarge_row(luf, i, vr_len[i] + 10)) { /* overflow of the sparse vector area */ fhv->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; xassert(luf->new_sva > luf->sv_size); ret = FHV_EROOM; goto done; } } /* add v[i,j] to i-th row */ i_ptr = vr_ptr[i] + vr_len[i]; sv_ind[i_ptr] = j; sv_val[i_ptr] = cc_val[ptr]; vr_len[i]++; /* adjust index k2 */ if (k2 < pp_col[i]) k2 = pp_col[i]; } /* capacity of j-th column (which is currently empty) should be not less than len locations */ if (vc_cap[j] < len) { if (luf_enlarge_col(luf, j, len)) { /* overflow of the sparse vector area */ fhv->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; xassert(luf->new_sva > luf->sv_size); ret = FHV_EROOM; goto done; } } /* add new elements of matrix V to j-th column list */ j_ptr = vc_ptr[j]; memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int)); memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double)); vc_len[j] = len; luf->nnz_v += len; /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and therefore the adjacent basis matrix is structurally singular */ if (k1 > k2) { fhv->valid = 0; ret = FHV_ESING; goto done; } /* perform implicit symmetric permutations of rows and columns of matrix U */ i = pp_row[k1], j = qq_col[k1]; for (k = k1; k < k2; k++) { pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k; qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k; } pp_row[k2] = i, pp_col[i] = k2; qq_col[k2] = j, qq_row[j] = k2; /* now i-th row of the matrix V is k2-th row of matrix U; since no pivoting is used, only this row will be transformed */ /* copy elements of i-th row of matrix V to the working array and remove these elements from matrix V */ for (j = 1; j <= m; j++) work[j] = 0.0; i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++) { /* get column index of v[i,j] */ j = sv_ind[i_ptr]; /* store v[i,j] to the working array */ work[j] = sv_val[i_ptr]; /* find v[i,j] in the j-th column */ j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */; xassert(j_ptr <= j_end); /* remove v[i,j] from the j-th column */ sv_ind[j_ptr] = sv_ind[j_end]; sv_val[j_ptr] = sv_val[j_end]; vc_len[j]--; } /* now i-th row of matrix V is empty */ luf->nnz_v -= vr_len[i]; vr_len[i] = 0; /* create the next row-like factor of the matrix H; this factor corresponds to i-th (transformed) row */ fhv->hh_nfs++; hh_ind[fhv->hh_nfs] = i; /* hh_ptr[] will be set later */ hh_len[fhv->hh_nfs] = 0; /* up to (k2 - k1) free locations are needed to add new elements to the non-trivial row of the row-like factor */ if (luf->sv_end - luf->sv_beg < k2 - k1) { luf_defrag_sva(luf); if (luf->sv_end - luf->sv_beg < k2 - k1) { /* overflow of the sparse vector area */ fhv->valid = luf->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; xassert(luf->new_sva > luf->sv_size); ret = FHV_EROOM; goto done; } } /* eliminate subdiagonal elements of matrix U */ for (k = k1; k < k2; k++) { /* v[p,q] = u[k,k] */ p = pp_row[k], q = qq_col[k]; /* this is the crucial point, where even tiny non-zeros should not be dropped */ if (work[q] == 0.0) continue; /* compute gaussian multiplier f = v[i,q] / v[p,q] */ f = work[q] / vr_piv[p]; /* perform gaussian transformation: (i-th row) := (i-th row) - f * (p-th row) in order to eliminate v[i,q] = u[k2,k] */ p_beg = vr_ptr[p]; p_end = p_beg + vr_len[p] - 1; for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++) work[sv_ind[p_ptr]] -= f * sv_val[p_ptr]; /* store new element (gaussian multiplier that corresponds to p-th row) in the current row-like factor */ luf->sv_end--; sv_ind[luf->sv_end] = p; sv_val[luf->sv_end] = f; hh_len[fhv->hh_nfs]++; } /* set pointer to the current row-like factor of the matrix H (if no elements were added to this factor, it is unity matrix and therefore can be discarded) */ if (hh_len[fhv->hh_nfs] == 0) fhv->hh_nfs--; else { hh_ptr[fhv->hh_nfs] = luf->sv_end; fhv->nnz_h += hh_len[fhv->hh_nfs]; } /* store new pivot which corresponds to u[k2,k2] */ vr_piv[i] = work[qq_col[k2]]; /* new elements of i-th row of matrix V (which are non-diagonal elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are contained in the working array; add them to matrix V */ len = 0; for (k = k2+1; k <= m; k++) { /* get column index and value of v[i,j] = u[k2,k] */ j = qq_col[k]; temp = work[j]; /* if v[i,j] is close to zero, skip it */ if (fabs(temp) < eps_tol) continue; /* at least one unused location is needed in j-th column */ if (vc_len[j] + 1 > vc_cap[j]) { if (luf_enlarge_col(luf, j, vc_len[j] + 10)) { /* overflow of the sparse vector area */ fhv->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; xassert(luf->new_sva > luf->sv_size); ret = FHV_EROOM; goto done; } } /* add v[i,j] to j-th column */ j_ptr = vc_ptr[j] + vc_len[j]; sv_ind[j_ptr] = i; sv_val[j_ptr] = temp; vc_len[j]++; /* also store v[i,j] to the auxiliary array */ len++, cc_ind[len] = j, cc_val[len] = temp; } /* capacity of i-th row (which is currently empty) should be not less than len locations */ if (vr_cap[i] < len) { if (luf_enlarge_row(luf, i, len)) { /* overflow of the sparse vector area */ fhv->valid = 0; luf->new_sva = luf->sv_size + luf->sv_size; xassert(luf->new_sva > luf->sv_size); ret = FHV_EROOM; goto done; } } /* add new elements to i-th row list */ i_ptr = vr_ptr[i]; memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int)); memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double)); vr_len[i] = len; luf->nnz_v += len; /* updating is finished; check that diagonal element u[k2,k2] is not very small in absolute value among other elements in k2-th row and k2-th column of matrix U = P*V*Q */ /* temp = max(|u[k2,*]|, |u[*,k2]|) */ temp = 0.0; /* walk through k2-th row of U which is i-th row of V */ i = pp_row[k2]; i_beg = vr_ptr[i]; i_end = i_beg + vr_len[i] - 1; for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++) if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]); /* walk through k2-th column of U which is j-th column of V */ j = qq_col[k2]; j_beg = vc_ptr[j]; j_end = j_beg + vc_len[j] - 1; for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++) if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]); /* check that u[k2,k2] is not very small */ if (fabs(vr_piv[i]) < upd_tol * temp) { /* the factorization seems to be inaccurate and therefore must be recomputed */ fhv->valid = 0; ret = FHV_ECHECK; goto done; } /* the factorization has been successfully updated */ ret = 0; done: /* return to the calling program */ return ret; }