void npp_dbnd_col(NPP *npp, NPPCOL *q) { /* process non-negative column with upper bound */ struct dbnd_col *info; NPPROW *p; NPPCOL *s; /* the column must be non-negative with upper bound */ xassert(q->lb == 0.0); xassert(q->ub > 0.0); xassert(q->ub != +DBL_MAX); /* create variable s */ s = npp_add_col(npp); s->is_int = q->is_int; s->lb = 0.0, s->ub = +DBL_MAX; /* create equality constraint (2) */ p = npp_add_row(npp); p->lb = p->ub = q->ub; npp_add_aij(npp, p, q, +1.0); npp_add_aij(npp, p, s, +1.0); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_dbnd_col, sizeof(struct dbnd_col)); info->q = q->j; info->s = s->j; /* remove upper bound of x[q] */ q->ub = +DBL_MAX; return; }
void npp_free_col(NPP *npp, NPPCOL *q) { /* process free (unbounded) column */ struct free_col *info; NPPCOL *s; NPPAIJ *aij; /* the column must be free */ xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX); /* variable x[q] becomes s' */ q->lb = 0.0, q->ub = +DBL_MAX; /* create variable s'' */ s = npp_add_col(npp); s->is_int = q->is_int; s->lb = 0.0, s->ub = +DBL_MAX; /* duplicate objective coefficient */ s->coef = -q->coef; /* duplicate column of the constraint matrix */ for (aij = q->ptr; aij != NULL; aij = aij->c_next) npp_add_aij(npp, aij->row, s, -aij->val); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_free_col, sizeof(struct free_col)); info->q = q->j; info->s = s->j; return; }
void npp_leq_row(NPP *npp, NPPROW *p) { /* process row of 'not greater than' type */ struct ineq_row *info; NPPCOL *s; /* the row must have upper bound */ xassert(p->ub != +DBL_MAX); xassert(p->lb < p->ub); /* create column for slack variable */ s = npp_add_col(npp); s->lb = 0.0; s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb); /* and add it to the transformed problem */ npp_add_aij(npp, p, s, +1.0); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_leq_row, sizeof(struct ineq_row)); info->p = p->i; info->s = s->j; /* replace the row by equality constraint */ p->lb = p->ub; return; }
void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol, int scaling) { /* load original problem into the preprocessor workspace */ int m = orig->m; int n = orig->n; NPPROW **link; int i, j; double dir; xassert(names == GLP_OFF || names == GLP_ON); xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP); xassert(scaling == GLP_OFF || scaling == GLP_ON); if (sol == GLP_MIP) xassert(!scaling); npp->orig_dir = orig->dir; if (npp->orig_dir == GLP_MIN) dir = +1.0; else if (npp->orig_dir == GLP_MAX) dir = -1.0; else xassert(npp != npp); npp->orig_m = m; npp->orig_n = n; npp->orig_nnz = orig->nnz; if (names && orig->name != NULL) { npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1); strcpy(npp->name, orig->name); } if (names && orig->obj != NULL) { npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1); strcpy(npp->obj, orig->obj); } npp->c0 = dir * orig->c0; /* load rows */ link = xcalloc(1+m, sizeof(NPPROW *)); for (i = 1; i <= m; i++) { GLPROW *rrr = orig->row[i]; NPPROW *row; link[i] = row = npp_add_row(npp); xassert(row->i == i); if (names && rrr->name != NULL) { row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1); strcpy(row->name, rrr->name); } if (!scaling) { if (rrr->type == GLP_FR) row->lb = -DBL_MAX, row->ub = +DBL_MAX; else if (rrr->type == GLP_LO) row->lb = rrr->lb, row->ub = +DBL_MAX; else if (rrr->type == GLP_UP) row->lb = -DBL_MAX, row->ub = rrr->ub; else if (rrr->type == GLP_DB) row->lb = rrr->lb, row->ub = rrr->ub; else if (rrr->type == GLP_FX) row->lb = row->ub = rrr->lb; else xassert(rrr != rrr); } else { double rii = rrr->rii; if (rrr->type == GLP_FR) row->lb = -DBL_MAX, row->ub = +DBL_MAX; else if (rrr->type == GLP_LO) row->lb = rrr->lb * rii, row->ub = +DBL_MAX; else if (rrr->type == GLP_UP) row->lb = -DBL_MAX, row->ub = rrr->ub * rii; else if (rrr->type == GLP_DB) row->lb = rrr->lb * rii, row->ub = rrr->ub * rii; else if (rrr->type == GLP_FX) row->lb = row->ub = rrr->lb * rii; else xassert(rrr != rrr); } } /* load columns and constraint coefficients */ for (j = 1; j <= n; j++) { GLPCOL *ccc = orig->col[j]; GLPAIJ *aaa; NPPCOL *col; col = npp_add_col(npp); xassert(col->j == j); if (names && ccc->name != NULL) { col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1); strcpy(col->name, ccc->name); } if (sol == GLP_MIP) #if 0 col->kind = ccc->kind; #else col->is_int = (char)(ccc->kind == GLP_IV); #endif if (!scaling) { if (ccc->type == GLP_FR) col->lb = -DBL_MAX, col->ub = +DBL_MAX; else if (ccc->type == GLP_LO) col->lb = ccc->lb, col->ub = +DBL_MAX; else if (ccc->type == GLP_UP) col->lb = -DBL_MAX, col->ub = ccc->ub; else if (ccc->type == GLP_DB) col->lb = ccc->lb, col->ub = ccc->ub; else if (ccc->type == GLP_FX) col->lb = col->ub = ccc->lb; else xassert(ccc != ccc); col->coef = dir * ccc->coef; for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next) npp_add_aij(npp, link[aaa->row->i], col, aaa->val); } else { double sjj = ccc->sjj; if (ccc->type == GLP_FR) col->lb = -DBL_MAX, col->ub = +DBL_MAX; else if (ccc->type == GLP_LO) col->lb = ccc->lb / sjj, col->ub = +DBL_MAX; else if (ccc->type == GLP_UP) col->lb = -DBL_MAX, col->ub = ccc->ub / sjj; else if (ccc->type == GLP_DB) col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj; else if (ccc->type == GLP_FX) col->lb = col->ub = ccc->lb / sjj; else xassert(ccc != ccc); col->coef = dir * ccc->coef * sjj; for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next) npp_add_aij(npp, link[aaa->row->i], col, aaa->row->rii * aaa->val * sjj); } } xfree(link); /* keep solution indicator and scaling option */ npp->sol = sol; npp->scaling = scaling; return; }
int npp_hidden_covering(NPP *npp, NPPROW *row) { /* identify hidden covering inequality */ NPPROW *copy; NPPAIJ *aij; struct elem *ptr, *e; int kase, ret, count = 0; double b; /* the row must be inequality constraint */ xassert(row->lb < row->ub); for (kase = 0; kase <= 1; kase++) { if (kase == 0) { /* process row lower bound */ if (row->lb == -DBL_MAX) continue; ptr = copy_form(npp, row, +1.0); b = + row->lb; } else { /* process row upper bound */ if (row->ub == +DBL_MAX) continue; ptr = copy_form(npp, row, -1.0); b = - row->ub; } /* now the inequality has the form "sum a[j] x[j] >= b" */ ret = hidden_covering(npp, ptr, &b); xassert(0 <= ret && ret <= 2); if (kase == 1 && ret == 1 || ret == 2) { /* the original inequality has been identified as hidden covering inequality */ count++; #ifdef GLP_DEBUG xprintf("Original constraint:\n"); for (aij = row->ptr; aij != NULL; aij = aij->r_next) xprintf(" %+g x%d", aij->val, aij->col->j); if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb); if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub); xprintf("\n"); xprintf("Equivalent covering inequality:\n"); for (e = ptr; e != NULL; e = e->next) xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j); xprintf(", >= %g\n", b); #endif if (row->lb == -DBL_MAX || row->ub == +DBL_MAX) { /* the original row is single-sided inequality; no copy is needed */ copy = NULL; } else { /* the original row is double-sided inequality; we need to create its copy for other bound before replacing it with the equivalent inequality */ copy = npp_add_row(npp); if (kase == 0) { /* the copy is for upper bound */ copy->lb = -DBL_MAX, copy->ub = row->ub; } else { /* the copy is for lower bound */ copy->lb = row->lb, copy->ub = +DBL_MAX; } /* copy original row coefficients */ for (aij = row->ptr; aij != NULL; aij = aij->r_next) npp_add_aij(npp, copy, aij->col, aij->val); } /* replace the original inequality by equivalent one */ npp_erase_row(npp, row); row->lb = b, row->ub = +DBL_MAX; for (e = ptr; e != NULL; e = e->next) npp_add_aij(npp, row, e->xj, e->aj); /* continue processing upper bound for the copy */ if (copy != NULL) row = copy; } drop_form(npp, ptr); } return count; }
int npp_reduce_ineq_coef(NPP *npp, NPPROW *row) { /* reduce inequality constraint coefficients */ NPPROW *copy; NPPAIJ *aij; struct elem *ptr, *e; int kase, count[2]; double b; /* the row must be inequality constraint */ xassert(row->lb < row->ub); count[0] = count[1] = 0; for (kase = 0; kase <= 1; kase++) { if (kase == 0) { /* process row lower bound */ if (row->lb == -DBL_MAX) continue; #ifdef GLP_DEBUG xprintf("L"); #endif ptr = copy_form(npp, row, +1.0); b = + row->lb; } else { /* process row upper bound */ if (row->ub == +DBL_MAX) continue; #ifdef GLP_DEBUG xprintf("U"); #endif ptr = copy_form(npp, row, -1.0); b = - row->ub; } /* now the inequality has the form "sum a[j] x[j] >= b" */ count[kase] = reduce_ineq_coef(npp, ptr, &b); if (count[kase] > 0) { /* the original inequality has been replaced by equivalent one with coefficients reduced */ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX) { /* the original row is single-sided inequality; no copy is needed */ copy = NULL; } else { /* the original row is double-sided inequality; we need to create its copy for other bound before replacing it with the equivalent inequality */ #ifdef GLP_DEBUG xprintf("*"); #endif copy = npp_add_row(npp); if (kase == 0) { /* the copy is for upper bound */ copy->lb = -DBL_MAX, copy->ub = row->ub; } else { /* the copy is for lower bound */ copy->lb = row->lb, copy->ub = +DBL_MAX; } /* copy original row coefficients */ for (aij = row->ptr; aij != NULL; aij = aij->r_next) npp_add_aij(npp, copy, aij->col, aij->val); } /* replace the original inequality by equivalent one */ npp_erase_row(npp, row); row->lb = b, row->ub = +DBL_MAX; for (e = ptr; e != NULL; e = e->next) npp_add_aij(npp, row, e->xj, e->aj); /* continue processing upper bound for the copy */ if (copy != NULL) row = copy; } drop_form(npp, ptr); } return count[0] + count[1]; }
int npp_binarize_prob(NPP *npp) { /* binarize MIP problem */ struct binarize *info; NPPROW *row; NPPCOL *col, *bin; NPPAIJ *aij; int u, n, k, temp, nfails, nvars, nbins, nrows; /* new variables will be added to the end of the column list, so we go from the end to beginning of the column list */ nfails = nvars = nbins = nrows = 0; for (col = npp->c_tail; col != NULL; col = col->prev) { /* skip continuous variable */ if (!col->is_int) continue; /* skip fixed variable */ if (col->lb == col->ub) continue; /* skip binary variable */ if (col->lb == 0.0 && col->ub == 1.0) continue; /* check if the transformation is applicable */ if (col->lb < -1e6 || col->ub > +1e6 || col->ub - col->lb > 4095.0) { /* unfortunately, not */ nfails++; continue; } /* process integer non-binary variable x[q] */ nvars++; /* make x[q] non-negative, if its lower bound is non-zero */ if (col->lb != 0.0) npp_lbnd_col(npp, col); /* now 0 <= x[q] <= u[q] */ xassert(col->lb == 0.0); u = (int)col->ub; xassert(col->ub == (double)u); /* if x[q] is binary, further processing is not needed */ if (u == 1) continue; /* determine smallest n such that u <= 2^n - 1 (thus, n is the number of binary variables needed) */ n = 2, temp = 4; while (u >= temp) n++, temp += temp; nbins += n; /* create transformation stack entry */ info = npp_push_tse(npp, rcv_binarize_prob, sizeof(struct binarize)); info->q = col->j; info->j = 0; /* will be set below */ info->n = n; /* if u < 2^n - 1, we need one additional row for (4) */ if (u < temp - 1) { row = npp_add_row(npp), nrows++; row->lb = -DBL_MAX, row->ub = u; } else row = NULL; /* in the transformed problem variable x[q] becomes binary variable x[0], so its objective and constraint coefficients are not changed */ col->ub = 1.0; /* include x[0] into constraint (4) */ if (row != NULL) npp_add_aij(npp, row, col, 1.0); /* add other binary variables x[1], ..., x[n-1] */ for (k = 1, temp = 2; k < n; k++, temp += temp) { /* add new binary variable x[k] */ bin = npp_add_col(npp); bin->is_int = 1; bin->lb = 0.0, bin->ub = 1.0; bin->coef = (double)temp * col->coef; /* store column reference number for x[1] */ if (info->j == 0) info->j = bin->j; else xassert(info->j + (k-1) == bin->j); /* duplicate constraint coefficients for x[k]; this also automatically includes x[k] into constraint (4) */ for (aij = col->ptr; aij != NULL; aij = aij->c_next) npp_add_aij(npp, aij->row, bin, (double)temp * aij->val); } } if (nvars > 0) xprintf("%d integer variable(s) were replaced by %d binary one" "s\n", nvars, nbins); if (nrows > 0) xprintf("%d row(s) were added due to binarization\n", nrows); if (nfails > 0) xprintf("Binarization failed for %d integer variable(s)\n", nfails); return nfails; }