123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434 |
- /* glpnpp02.c */
- /***********************************************************************
- * This code is part of GLPK (GNU Linear Programming Kit).
- *
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
- * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
- * E-mail: <mao@gnu.org>.
- *
- * GLPK is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GLPK is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
- #include "glpnpp.h"
- /***********************************************************************
- * NAME
- *
- * npp_free_row - process free (unbounded) row
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_free_row(NPP *npp, NPPROW *p);
- *
- * DESCRIPTION
- *
- * The routine npp_free_row processes row p, which is free (i.e. has
- * no finite bounds):
- *
- * -inf < sum a[p,j] x[j] < +inf. (1)
- * j
- *
- * PROBLEM TRANSFORMATION
- *
- * Constraint (1) cannot be active, so it is redundant and can be
- * removed from the original problem.
- *
- * Removing row p leads to removing a column of multiplier pi[p] for
- * this row in the dual system. Since row p has no bounds, pi[p] = 0,
- * so removing the column does not affect the dual solution.
- *
- * RECOVERING BASIC SOLUTION
- *
- * In solution to the original problem row p is inactive constraint,
- * so it is assigned status GLP_BS, and multiplier pi[p] is assigned
- * zero value.
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * In solution to the original problem row p is inactive constraint,
- * so its multiplier pi[p] is assigned zero value.
- *
- * RECOVERING MIP SOLUTION
- *
- * None needed. */
- struct free_row
- { /* free (unbounded) row */
- int p;
- /* row reference number */
- };
- static int rcv_free_row(NPP *npp, void *info);
- void npp_free_row(NPP *npp, NPPROW *p)
- { /* process free (unbounded) row */
- struct free_row *info;
- /* the row must be free */
- xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_free_row, sizeof(struct free_row));
- info->p = p->i;
- /* remove the row from the problem */
- npp_del_row(npp, p);
- return;
- }
- static int rcv_free_row(NPP *npp, void *_info)
- { /* recover free (unbounded) row */
- struct free_row *info = _info;
- if (npp->sol == GLP_SOL)
- npp->r_stat[info->p] = GLP_BS;
- if (npp->sol != GLP_MIP)
- npp->r_pi[info->p] = 0.0;
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_geq_row - process row of 'not less than' type
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_geq_row(NPP *npp, NPPROW *p);
- *
- * DESCRIPTION
- *
- * The routine npp_geq_row processes row p, which is 'not less than'
- * inequality constraint:
- *
- * L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
- * j
- *
- * where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
- *
- * PROBLEM TRANSFORMATION
- *
- * Constraint (1) can be replaced by equality constraint:
- *
- * sum a[p,j] x[j] - s = L[p], (2)
- * j
- *
- * where
- *
- * 0 <= s (<= U[p] - L[p]) (3)
- *
- * is a non-negative surplus variable.
- *
- * Since in the primal system there appears column s having the only
- * non-zero coefficient in row p, in the dual system there appears a
- * new row:
- *
- * (-1) pi[p] + lambda = 0, (4)
- *
- * where (-1) is coefficient of column s in row p, pi[p] is multiplier
- * of row p, lambda is multiplier of column q, 0 is coefficient of
- * column s in the objective row.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Status of row p in solution to the original problem is determined
- * by its status and status of column q in solution to the transformed
- * problem as follows:
- *
- * +--------------------------------------+------------------+
- * | Transformed problem | Original problem |
- * +-----------------+--------------------+------------------+
- * | Status of row p | Status of column s | Status of row p |
- * +-----------------+--------------------+------------------+
- * | GLP_BS | GLP_BS | N/A |
- * | GLP_BS | GLP_NL | GLP_BS |
- * | GLP_BS | GLP_NU | GLP_BS |
- * | GLP_NS | GLP_BS | GLP_BS |
- * | GLP_NS | GLP_NL | GLP_NL |
- * | GLP_NS | GLP_NU | GLP_NU |
- * +-----------------+--------------------+------------------+
- *
- * Value of row multiplier pi[p] in solution to the original problem
- * is the same as in solution to the transformed problem.
- *
- * 1. In solution to the transformed problem row p and column q cannot
- * be basic at the same time; otherwise the basis matrix would have
- * two linear dependent columns: unity column of auxiliary variable
- * of row p and unity column of variable s.
- *
- * 2. Though in the transformed problem row p is equality constraint,
- * it may be basic due to primal degenerate solution.
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of row multiplier pi[p] in solution to the original problem
- * is the same as in solution to the transformed problem.
- *
- * RECOVERING MIP SOLUTION
- *
- * None needed. */
- struct ineq_row
- { /* inequality constraint row */
- int p;
- /* row reference number */
- int s;
- /* column reference number for slack/surplus variable */
- };
- static int rcv_geq_row(NPP *npp, void *info);
- void npp_geq_row(NPP *npp, NPPROW *p)
- { /* process row of 'not less than' type */
- struct ineq_row *info;
- NPPCOL *s;
- /* the row must have lower bound */
- xassert(p->lb != -DBL_MAX);
- xassert(p->lb < p->ub);
- /* create column for surplus variable */
- s = npp_add_col(npp);
- s->lb = 0.0;
- s->ub = (p->ub == +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_geq_row, sizeof(struct ineq_row));
- info->p = p->i;
- info->s = s->j;
- /* replace the row by equality constraint */
- p->ub = p->lb;
- return;
- }
- static int rcv_geq_row(NPP *npp, void *_info)
- { /* recover row of 'not less than' type */
- struct ineq_row *info = _info;
- if (npp->sol == GLP_SOL)
- { if (npp->r_stat[info->p] == GLP_BS)
- { if (npp->c_stat[info->s] == GLP_BS)
- { npp_error();
- return 1;
- }
- else if (npp->c_stat[info->s] == GLP_NL ||
- npp->c_stat[info->s] == GLP_NU)
- npp->r_stat[info->p] = GLP_BS;
- else
- { npp_error();
- return 1;
- }
- }
- else if (npp->r_stat[info->p] == GLP_NS)
- { if (npp->c_stat[info->s] == GLP_BS)
- npp->r_stat[info->p] = GLP_BS;
- else if (npp->c_stat[info->s] == GLP_NL)
- npp->r_stat[info->p] = GLP_NL;
- else if (npp->c_stat[info->s] == GLP_NU)
- npp->r_stat[info->p] = GLP_NU;
- else
- { npp_error();
- return 1;
- }
- }
- else
- { npp_error();
- return 1;
- }
- }
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_leq_row - process row of 'not greater than' type
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_leq_row(NPP *npp, NPPROW *p);
- *
- * DESCRIPTION
- *
- * The routine npp_leq_row processes row p, which is 'not greater than'
- * inequality constraint:
- *
- * (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
- * j
- *
- * where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
- *
- * PROBLEM TRANSFORMATION
- *
- * Constraint (1) can be replaced by equality constraint:
- *
- * sum a[p,j] x[j] + s = L[p], (2)
- * j
- *
- * where
- *
- * 0 <= s (<= U[p] - L[p]) (3)
- *
- * is a non-negative slack variable.
- *
- * Since in the primal system there appears column s having the only
- * non-zero coefficient in row p, in the dual system there appears a
- * new row:
- *
- * (+1) pi[p] + lambda = 0, (4)
- *
- * where (+1) is coefficient of column s in row p, pi[p] is multiplier
- * of row p, lambda is multiplier of column q, 0 is coefficient of
- * column s in the objective row.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Status of row p in solution to the original problem is determined
- * by its status and status of column q in solution to the transformed
- * problem as follows:
- *
- * +--------------------------------------+------------------+
- * | Transformed problem | Original problem |
- * +-----------------+--------------------+------------------+
- * | Status of row p | Status of column s | Status of row p |
- * +-----------------+--------------------+------------------+
- * | GLP_BS | GLP_BS | N/A |
- * | GLP_BS | GLP_NL | GLP_BS |
- * | GLP_BS | GLP_NU | GLP_BS |
- * | GLP_NS | GLP_BS | GLP_BS |
- * | GLP_NS | GLP_NL | GLP_NU |
- * | GLP_NS | GLP_NU | GLP_NL |
- * +-----------------+--------------------+------------------+
- *
- * Value of row multiplier pi[p] in solution to the original problem
- * is the same as in solution to the transformed problem.
- *
- * 1. In solution to the transformed problem row p and column q cannot
- * be basic at the same time; otherwise the basis matrix would have
- * two linear dependent columns: unity column of auxiliary variable
- * of row p and unity column of variable s.
- *
- * 2. Though in the transformed problem row p is equality constraint,
- * it may be basic due to primal degeneracy.
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of row multiplier pi[p] in solution to the original problem
- * is the same as in solution to the transformed problem.
- *
- * RECOVERING MIP SOLUTION
- *
- * None needed. */
- static int rcv_leq_row(NPP *npp, void *info);
- 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;
- }
- static int rcv_leq_row(NPP *npp, void *_info)
- { /* recover row of 'not greater than' type */
- struct ineq_row *info = _info;
- if (npp->sol == GLP_SOL)
- { if (npp->r_stat[info->p] == GLP_BS)
- { if (npp->c_stat[info->s] == GLP_BS)
- { npp_error();
- return 1;
- }
- else if (npp->c_stat[info->s] == GLP_NL ||
- npp->c_stat[info->s] == GLP_NU)
- npp->r_stat[info->p] = GLP_BS;
- else
- { npp_error();
- return 1;
- }
- }
- else if (npp->r_stat[info->p] == GLP_NS)
- { if (npp->c_stat[info->s] == GLP_BS)
- npp->r_stat[info->p] = GLP_BS;
- else if (npp->c_stat[info->s] == GLP_NL)
- npp->r_stat[info->p] = GLP_NU;
- else if (npp->c_stat[info->s] == GLP_NU)
- npp->r_stat[info->p] = GLP_NL;
- else
- { npp_error();
- return 1;
- }
- }
- else
- { npp_error();
- return 1;
- }
- }
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_free_col - process free (unbounded) column
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_free_col(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_free_col processes column q, which is free (i.e. has
- * no finite bounds):
- *
- * -oo < x[q] < +oo. (1)
- *
- * PROBLEM TRANSFORMATION
- *
- * Free (unbounded) variable can be replaced by the difference of two
- * non-negative variables:
- *
- * x[q] = s' - s'', s', s'' >= 0. (2)
- *
- * Assuming that in the transformed problem x[q] becomes s',
- * transformation (2) causes new column s'' to appear, which differs
- * from column s' only in the sign of coefficients in constraint and
- * objective rows. Thus, if in the dual system the following row
- * corresponds to column s':
- *
- * sum a[i,q] pi[i] + lambda' = c[q], (3)
- * i
- *
- * the row which corresponds to column s'' is the following:
- *
- * sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
- * i
- *
- * Then from (3) and (4) it follows that:
- *
- * lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
- *
- * where lambda' and lambda'' are multipliers for columns s' and s'',
- * resp.
- *
- * RECOVERING BASIC SOLUTION
- *
- * With respect to (5) status of column q in solution to the original
- * problem is determined by statuses of columns s' and s'' in solution
- * to the transformed problem as follows:
- *
- * +--------------------------------------+------------------+
- * | Transformed problem | Original problem |
- * +------------------+-------------------+------------------+
- * | Status of col s' | Status of col s'' | Status of col q |
- * +------------------+-------------------+------------------+
- * | GLP_BS | GLP_BS | N/A |
- * | GLP_BS | GLP_NL | GLP_BS |
- * | GLP_NL | GLP_BS | GLP_BS |
- * | GLP_NL | GLP_NL | GLP_NF |
- * +------------------+-------------------+------------------+
- *
- * Value of column q is computed with formula (2).
- *
- * 1. In solution to the transformed problem columns s' and s'' cannot
- * be basic at the same time, because they differ only in the sign,
- * hence, are linear dependent.
- *
- * 2. Though column q is free, it can be non-basic due to dual
- * degeneracy.
- *
- * 3. If column q is integral, columns s' and s'' are also integral.
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of column q is computed with formula (2).
- *
- * RECOVERING MIP SOLUTION
- *
- * Value of column q is computed with formula (2). */
- struct free_col
- { /* free (unbounded) column */
- int q;
- /* column reference number for variables x[q] and s' */
- int s;
- /* column reference number for variable s'' */
- };
- static int rcv_free_col(NPP *npp, void *info);
- 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;
- }
- static int rcv_free_col(NPP *npp, void *_info)
- { /* recover free (unbounded) column */
- struct free_col *info = _info;
- if (npp->sol == GLP_SOL)
- { if (npp->c_stat[info->q] == GLP_BS)
- { if (npp->c_stat[info->s] == GLP_BS)
- { npp_error();
- return 1;
- }
- else if (npp->c_stat[info->s] == GLP_NL)
- npp->c_stat[info->q] = GLP_BS;
- else
- { npp_error();
- return -1;
- }
- }
- else if (npp->c_stat[info->q] == GLP_NL)
- { if (npp->c_stat[info->s] == GLP_BS)
- npp->c_stat[info->q] = GLP_BS;
- else if (npp->c_stat[info->s] == GLP_NL)
- npp->c_stat[info->q] = GLP_NF;
- else
- { npp_error();
- return -1;
- }
- }
- else
- { npp_error();
- return -1;
- }
- }
- /* compute value of x[q] with formula (2) */
- npp->c_value[info->q] -= npp->c_value[info->s];
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_lbnd_col - process column with (non-zero) lower bound
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_lbnd_col(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_lbnd_col processes column q, which has (non-zero)
- * lower bound:
- *
- * l[q] <= x[q] (<= u[q]), (1)
- *
- * where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
- *
- * PROBLEM TRANSFORMATION
- *
- * Column q can be replaced as follows:
- *
- * x[q] = l[q] + s, (2)
- *
- * where
- *
- * 0 <= s (<= u[q] - l[q]) (3)
- *
- * is a non-negative variable.
- *
- * Substituting x[q] from (2) into the objective row, we have:
- *
- * z = sum c[j] x[j] + c0 =
- * j
- *
- * = sum c[j] x[j] + c[q] x[q] + c0 =
- * j!=q
- *
- * = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
- * j!=q
- *
- * = sum c[j] x[j] + c[q] s + c~0,
- *
- * where
- *
- * c~0 = c0 + c[q] l[q] (4)
- *
- * is the constant term of the objective in the transformed problem.
- * Similarly, substituting x[q] into constraint row i, we have:
- *
- * L[i] <= sum a[i,j] x[j] <= U[i] ==>
- * j
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
- * j!=q
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
- * j!=q
- *
- * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
- * j!=q
- *
- * where
- *
- * L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
- *
- * are lower and upper bounds of row i in the transformed problem,
- * resp.
- *
- * Transformation (2) does not affect the dual system.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Status of column q in solution to the original problem is the same
- * as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
- * Value of column q is computed with formula (2).
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of column q is computed with formula (2).
- *
- * RECOVERING MIP SOLUTION
- *
- * Value of column q is computed with formula (2). */
- struct bnd_col
- { /* bounded column */
- int q;
- /* column reference number for variables x[q] and s */
- double bnd;
- /* lower/upper bound l[q] or u[q] */
- };
- static int rcv_lbnd_col(NPP *npp, void *info);
- void npp_lbnd_col(NPP *npp, NPPCOL *q)
- { /* process column with (non-zero) lower bound */
- struct bnd_col *info;
- NPPROW *i;
- NPPAIJ *aij;
- /* the column must have non-zero lower bound */
- xassert(q->lb != 0.0);
- xassert(q->lb != -DBL_MAX);
- xassert(q->lb < q->ub);
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_lbnd_col, sizeof(struct bnd_col));
- info->q = q->j;
- info->bnd = q->lb;
- /* substitute x[q] into objective row */
- npp->c0 += q->coef * q->lb;
- /* substitute x[q] into constraint rows */
- for (aij = q->ptr; aij != NULL; aij = aij->c_next)
- { i = aij->row;
- if (i->lb == i->ub)
- i->ub = (i->lb -= aij->val * q->lb);
- else
- { if (i->lb != -DBL_MAX)
- i->lb -= aij->val * q->lb;
- if (i->ub != +DBL_MAX)
- i->ub -= aij->val * q->lb;
- }
- }
- /* column x[q] becomes column s */
- if (q->ub != +DBL_MAX)
- q->ub -= q->lb;
- q->lb = 0.0;
- return;
- }
- static int rcv_lbnd_col(NPP *npp, void *_info)
- { /* recover column with (non-zero) lower bound */
- struct bnd_col *info = _info;
- if (npp->sol == GLP_SOL)
- { if (npp->c_stat[info->q] == GLP_BS ||
- npp->c_stat[info->q] == GLP_NL ||
- npp->c_stat[info->q] == GLP_NU)
- npp->c_stat[info->q] = npp->c_stat[info->q];
- else
- { npp_error();
- return 1;
- }
- }
- /* compute value of x[q] with formula (2) */
- npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_ubnd_col - process column with upper bound
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_ubnd_col(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_ubnd_col processes column q, which has upper bound:
- *
- * (l[q] <=) x[q] <= u[q], (1)
- *
- * where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
- *
- * PROBLEM TRANSFORMATION
- *
- * Column q can be replaced as follows:
- *
- * x[q] = u[q] - s, (2)
- *
- * where
- *
- * 0 <= s (<= u[q] - l[q]) (3)
- *
- * is a non-negative variable.
- *
- * Substituting x[q] from (2) into the objective row, we have:
- *
- * z = sum c[j] x[j] + c0 =
- * j
- *
- * = sum c[j] x[j] + c[q] x[q] + c0 =
- * j!=q
- *
- * = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
- * j!=q
- *
- * = sum c[j] x[j] - c[q] s + c~0,
- *
- * where
- *
- * c~0 = c0 + c[q] u[q] (4)
- *
- * is the constant term of the objective in the transformed problem.
- * Similarly, substituting x[q] into constraint row i, we have:
- *
- * L[i] <= sum a[i,j] x[j] <= U[i] ==>
- * j
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
- * j!=q
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
- * j!=q
- *
- * L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
- * j!=q
- *
- * where
- *
- * L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
- *
- * are lower and upper bounds of row i in the transformed problem,
- * resp.
- *
- * Note that in the transformed problem coefficients c[q] and a[i,q]
- * change their sign. Thus, the row of the dual system corresponding to
- * column q:
- *
- * sum a[i,q] pi[i] + lambda[q] = c[q] (6)
- * i
- *
- * in the transformed problem becomes the following:
- *
- * sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
- * i
- *
- * Therefore:
- *
- * lambda[q] = - lambda[s], (8)
- *
- * where lambda[q] is multiplier for column q, lambda[s] is multiplier
- * for column s.
- *
- * RECOVERING BASIC SOLUTION
- *
- * With respect to (8) status of column q in solution to the original
- * problem is determined by status of column s in solution to the
- * transformed problem as follows:
- *
- * +-----------------------+--------------------+
- * | Status of column s | Status of column q |
- * | (transformed problem) | (original problem) |
- * +-----------------------+--------------------+
- * | GLP_BS | GLP_BS |
- * | GLP_NL | GLP_NU |
- * | GLP_NU | GLP_NL |
- * +-----------------------+--------------------+
- *
- * Value of column q is computed with formula (2).
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of column q is computed with formula (2).
- *
- * RECOVERING MIP SOLUTION
- *
- * Value of column q is computed with formula (2). */
- static int rcv_ubnd_col(NPP *npp, void *info);
- void npp_ubnd_col(NPP *npp, NPPCOL *q)
- { /* process column with upper bound */
- struct bnd_col *info;
- NPPROW *i;
- NPPAIJ *aij;
- /* the column must have upper bound */
- xassert(q->ub != +DBL_MAX);
- xassert(q->lb < q->ub);
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_ubnd_col, sizeof(struct bnd_col));
- info->q = q->j;
- info->bnd = q->ub;
- /* substitute x[q] into objective row */
- npp->c0 += q->coef * q->ub;
- q->coef = -q->coef;
- /* substitute x[q] into constraint rows */
- for (aij = q->ptr; aij != NULL; aij = aij->c_next)
- { i = aij->row;
- if (i->lb == i->ub)
- i->ub = (i->lb -= aij->val * q->ub);
- else
- { if (i->lb != -DBL_MAX)
- i->lb -= aij->val * q->ub;
- if (i->ub != +DBL_MAX)
- i->ub -= aij->val * q->ub;
- }
- aij->val = -aij->val;
- }
- /* column x[q] becomes column s */
- if (q->lb != -DBL_MAX)
- q->ub -= q->lb;
- else
- q->ub = +DBL_MAX;
- q->lb = 0.0;
- return;
- }
- static int rcv_ubnd_col(NPP *npp, void *_info)
- { /* recover column with upper bound */
- struct bnd_col *info = _info;
- if (npp->sol == GLP_BS)
- { if (npp->c_stat[info->q] == GLP_BS)
- npp->c_stat[info->q] = GLP_BS;
- else if (npp->c_stat[info->q] == GLP_NL)
- npp->c_stat[info->q] = GLP_NU;
- else if (npp->c_stat[info->q] == GLP_NU)
- npp->c_stat[info->q] = GLP_NL;
- else
- { npp_error();
- return 1;
- }
- }
- /* compute value of x[q] with formula (2) */
- npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_dbnd_col - process non-negative column with upper bound
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_dbnd_col(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_dbnd_col processes column q, which is non-negative
- * and has upper bound:
- *
- * 0 <= x[q] <= u[q], (1)
- *
- * where u[q] > 0.
- *
- * PROBLEM TRANSFORMATION
- *
- * Upper bound of column q can be replaced by the following equality
- * constraint:
- *
- * x[q] + s = u[q], (2)
- *
- * where s >= 0 is a non-negative complement variable.
- *
- * Since in the primal system along with new row (2) there appears a
- * new column s having the only non-zero coefficient in this row, in
- * the dual system there appears a new row:
- *
- * (+1)pi + lambda[s] = 0, (3)
- *
- * where (+1) is coefficient at column s in row (2), pi is multiplier
- * for row (2), lambda[s] is multiplier for column s, 0 is coefficient
- * at column s in the objective row.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Status of column q in solution to the original problem is determined
- * by its status and status of column s in solution to the transformed
- * problem as follows:
- *
- * +-----------------------------------+------------------+
- * | Transformed problem | Original problem |
- * +-----------------+-----------------+------------------+
- * | Status of col q | Status of col s | Status of col q |
- * +-----------------+-----------------+------------------+
- * | GLP_BS | GLP_BS | GLP_BS |
- * | GLP_BS | GLP_NL | GLP_NU |
- * | GLP_NL | GLP_BS | GLP_NL |
- * | GLP_NL | GLP_NL | GLP_NL (*) |
- * +-----------------+-----------------+------------------+
- *
- * Value of column q in solution to the original problem is the same as
- * in solution to the transformed problem.
- *
- * 1. Formally, in solution to the transformed problem columns q and s
- * cannot be non-basic at the same time, since the constraint (2)
- * would be violated. However, if u[q] is close to zero, violation
- * may be less than a working precision even if both columns q and s
- * are non-basic. In this degenerate case row (2) can be only basic,
- * i.e. non-active constraint (otherwise corresponding row of the
- * basis matrix would be zero). This allows to pivot out auxiliary
- * variable and pivot in column s, in which case the row becomes
- * active while column s becomes basic.
- *
- * 2. If column q is integral, column s is also integral.
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of column q in solution to the original problem is the same as
- * in solution to the transformed problem.
- *
- * RECOVERING MIP SOLUTION
- *
- * Value of column q in solution to the original problem is the same as
- * in solution to the transformed problem. */
- struct dbnd_col
- { /* double-bounded column */
- int q;
- /* column reference number for variable x[q] */
- int s;
- /* column reference number for complement variable s */
- };
- static int rcv_dbnd_col(NPP *npp, void *info);
- 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;
- }
- static int rcv_dbnd_col(NPP *npp, void *_info)
- { /* recover non-negative column with upper bound */
- struct dbnd_col *info = _info;
- if (npp->sol == GLP_BS)
- { if (npp->c_stat[info->q] == GLP_BS)
- { if (npp->c_stat[info->s] == GLP_BS)
- npp->c_stat[info->q] = GLP_BS;
- else if (npp->c_stat[info->s] == GLP_NL)
- npp->c_stat[info->q] = GLP_NU;
- else
- { npp_error();
- return 1;
- }
- }
- else if (npp->c_stat[info->q] == GLP_NL)
- { if (npp->c_stat[info->s] == GLP_BS ||
- npp->c_stat[info->s] == GLP_NL)
- npp->c_stat[info->q] = GLP_NL;
- else
- { npp_error();
- return 1;
- }
- }
- else
- { npp_error();
- return 1;
- }
- }
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_fixed_col - process fixed column
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * void npp_fixed_col(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_fixed_col processes column q, which is fixed:
- *
- * x[q] = s[q], (1)
- *
- * where s[q] is a fixed column value.
- *
- * PROBLEM TRANSFORMATION
- *
- * The value of a fixed column can be substituted into the objective
- * and constraint rows that allows removing the column from the problem.
- *
- * Substituting x[q] = s[q] into the objective row, we have:
- *
- * z = sum c[j] x[j] + c0 =
- * j
- *
- * = sum c[j] x[j] + c[q] x[q] + c0 =
- * j!=q
- *
- * = sum c[j] x[j] + c[q] s[q] + c0 =
- * j!=q
- *
- * = sum c[j] x[j] + c~0,
- * j!=q
- *
- * where
- *
- * c~0 = c0 + c[q] s[q] (2)
- *
- * is the constant term of the objective in the transformed problem.
- * Similarly, substituting x[q] = s[q] into constraint row i, we have:
- *
- * L[i] <= sum a[i,j] x[j] <= U[i] ==>
- * j
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
- * j!=q
- *
- * L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
- * j!=q
- *
- * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
- * j!=q
- *
- * where
- *
- * L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
- *
- * are lower and upper bounds of row i in the transformed problem,
- * resp.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Column q is assigned status GLP_NS and its value is assigned s[q].
- *
- * RECOVERING INTERIOR-POINT SOLUTION
- *
- * Value of column q is assigned s[q].
- *
- * RECOVERING MIP SOLUTION
- *
- * Value of column q is assigned s[q]. */
- struct fixed_col
- { /* fixed column */
- int q;
- /* column reference number for variable x[q] */
- double s;
- /* value, at which x[q] is fixed */
- };
- static int rcv_fixed_col(NPP *npp, void *info);
- void npp_fixed_col(NPP *npp, NPPCOL *q)
- { /* process fixed column */
- struct fixed_col *info;
- NPPROW *i;
- NPPAIJ *aij;
- /* the column must be fixed */
- xassert(q->lb == q->ub);
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_fixed_col, sizeof(struct fixed_col));
- info->q = q->j;
- info->s = q->lb;
- /* substitute x[q] = s[q] into objective row */
- npp->c0 += q->coef * q->lb;
- /* substitute x[q] = s[q] into constraint rows */
- for (aij = q->ptr; aij != NULL; aij = aij->c_next)
- { i = aij->row;
- if (i->lb == i->ub)
- i->ub = (i->lb -= aij->val * q->lb);
- else
- { if (i->lb != -DBL_MAX)
- i->lb -= aij->val * q->lb;
- if (i->ub != +DBL_MAX)
- i->ub -= aij->val * q->lb;
- }
- }
- /* remove the column from the problem */
- npp_del_col(npp, q);
- return;
- }
- static int rcv_fixed_col(NPP *npp, void *_info)
- { /* recover fixed column */
- struct fixed_col *info = _info;
- if (npp->sol == GLP_SOL)
- npp->c_stat[info->q] = GLP_NS;
- npp->c_value[info->q] = info->s;
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_make_equality - process row with almost identical bounds
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * int npp_make_equality(NPP *npp, NPPROW *p);
- *
- * DESCRIPTION
- *
- * The routine npp_make_equality processes row p:
- *
- * L[p] <= sum a[p,j] x[j] <= U[p], (1)
- * j
- *
- * where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
- * constraint.
- *
- * RETURNS
- *
- * 0 - row bounds have not been changed;
- *
- * 1 - row has been replaced by equality constraint.
- *
- * PROBLEM TRANSFORMATION
- *
- * If bounds of row (1) are very close to each other:
- *
- * U[p] - L[p] <= eps, (2)
- *
- * where eps is an absolute tolerance for row value, the row can be
- * replaced by the following almost equivalent equiality constraint:
- *
- * sum a[p,j] x[j] = b, (3)
- * j
- *
- * where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
- * to be very close to its nearest integer:
- *
- * |b - floor(b + 0.5)| <= eps, (4)
- *
- * it is reasonable to use this nearest integer as the right-hand side.
- *
- * RECOVERING BASIC SOLUTION
- *
- * Status of row p in solution to the original problem is determined
- * by its status and the sign of its multiplier pi[p] in solution to
- * the transformed problem as follows:
- *
- * +-----------------------+---------+--------------------+
- * | Status of row p | Sign of | Status of row p |
- * | (transformed problem) | pi[p] | (original problem) |
- * +-----------------------+---------+--------------------+
- * | GLP_BS | + / - | GLP_BS |
- * | GLP_NS | + | GLP_NL |
- * | GLP_NS | - | GLP_NU |
- * +-----------------------+---------+--------------------+
- *
- * Value of row multiplier pi[p] in solution to the original problem is
- * the same as in solution to the transformed problem.
- *
- * RECOVERING INTERIOR POINT SOLUTION
- *
- * Value of row multiplier pi[p] in solution to the original problem is
- * the same as in solution to the transformed problem.
- *
- * RECOVERING MIP SOLUTION
- *
- * None needed. */
- struct make_equality
- { /* row with almost identical bounds */
- int p;
- /* row reference number */
- };
- static int rcv_make_equality(NPP *npp, void *info);
- int npp_make_equality(NPP *npp, NPPROW *p)
- { /* process row with almost identical bounds */
- struct make_equality *info;
- double b, eps, nint;
- /* the row must be double-sided inequality */
- xassert(p->lb != -DBL_MAX);
- xassert(p->ub != +DBL_MAX);
- xassert(p->lb < p->ub);
- /* check row bounds */
- eps = 1e-9 + 1e-12 * fabs(p->lb);
- if (p->ub - p->lb > eps) return 0;
- /* row bounds are very close to each other */
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_make_equality, sizeof(struct make_equality));
- info->p = p->i;
- /* compute right-hand side */
- b = 0.5 * (p->ub + p->lb);
- nint = floor(b + 0.5);
- if (fabs(b - nint) <= eps) b = nint;
- /* replace row p by almost equivalent equality constraint */
- p->lb = p->ub = b;
- return 1;
- }
- int rcv_make_equality(NPP *npp, void *_info)
- { /* recover row with almost identical bounds */
- struct make_equality *info = _info;
- if (npp->sol == GLP_SOL)
- { if (npp->r_stat[info->p] == GLP_BS)
- npp->r_stat[info->p] = GLP_BS;
- else if (npp->r_stat[info->p] == GLP_NS)
- { if (npp->r_pi[info->p] >= 0.0)
- npp->r_stat[info->p] = GLP_NL;
- else
- npp->r_stat[info->p] = GLP_NU;
- }
- else
- { npp_error();
- return 1;
- }
- }
- return 0;
- }
- /***********************************************************************
- * NAME
- *
- * npp_make_fixed - process column with almost identical bounds
- *
- * SYNOPSIS
- *
- * #include "glpnpp.h"
- * int npp_make_fixed(NPP *npp, NPPCOL *q);
- *
- * DESCRIPTION
- *
- * The routine npp_make_fixed processes column q:
- *
- * l[q] <= x[q] <= u[q], (1)
- *
- * where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
- * bounds.
- *
- * RETURNS
- *
- * 0 - column bounds have not been changed;
- *
- * 1 - column has been fixed.
- *
- * PROBLEM TRANSFORMATION
- *
- * If bounds of column (1) are very close to each other:
- *
- * u[q] - l[q] <= eps, (2)
- *
- * where eps is an absolute tolerance for column value, the column can
- * be fixed:
- *
- * x[q] = s[q], (3)
- *
- * where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
- * happens to be very close to its nearest integer:
- *
- * |s[q] - floor(s[q] + 0.5)| <= eps, (4)
- *
- * it is reasonable to use this nearest integer as the fixed value.
- *
- * RECOVERING BASIC SOLUTION
- *
- * In the dual system of the original (as well as transformed) problem
- * column q corresponds to the following row:
- *
- * sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
- * i
- *
- * Since multipliers pi[i] are known for all rows from solution to the
- * transformed problem, formula (5) allows computing value of multiplier
- * (reduced cost) for column q:
- *
- * lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
- * i
- *
- * Status of column q in solution to the original problem is determined
- * by its status and the sign of its multiplier lambda[q] in solution to
- * the transformed problem as follows:
- *
- * +-----------------------+-----------+--------------------+
- * | Status of column q | Sign of | Status of column q |
- * | (transformed problem) | lambda[q] | (original problem) |
- * +-----------------------+-----------+--------------------+
- * | GLP_BS | + / - | GLP_BS |
- * | GLP_NS | + | GLP_NL |
- * | GLP_NS | - | GLP_NU |
- * +-----------------------+-----------+--------------------+
- *
- * Value of column q in solution to the original problem is the same as
- * in solution to the transformed problem.
- *
- * RECOVERING INTERIOR POINT SOLUTION
- *
- * Value of column q in solution to the original problem is the same as
- * in solution to the transformed problem.
- *
- * RECOVERING MIP SOLUTION
- *
- * None needed. */
- struct make_fixed
- { /* column with almost identical bounds */
- int q;
- /* column reference number */
- double c;
- /* objective coefficient at x[q] */
- NPPLFE *ptr;
- /* list of non-zero coefficients a[i,q] */
- };
- static int rcv_make_fixed(NPP *npp, void *info);
- int npp_make_fixed(NPP *npp, NPPCOL *q)
- { /* process column with almost identical bounds */
- struct make_fixed *info;
- NPPAIJ *aij;
- NPPLFE *lfe;
- double s, eps, nint;
- /* the column must be double-bounded */
- xassert(q->lb != -DBL_MAX);
- xassert(q->ub != +DBL_MAX);
- xassert(q->lb < q->ub);
- /* check column bounds */
- eps = 1e-9 + 1e-12 * fabs(q->lb);
- if (q->ub - q->lb > eps) return 0;
- /* column bounds are very close to each other */
- /* create transformation stack entry */
- info = npp_push_tse(npp,
- rcv_make_fixed, sizeof(struct make_fixed));
- info->q = q->j;
- info->c = q->coef;
- info->ptr = NULL;
- /* save column coefficients a[i,q] (needed for basic solution
- only) */
- if (npp->sol == GLP_SOL)
- { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
- { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
- lfe->ref = aij->row->i;
- lfe->val = aij->val;
- lfe->next = info->ptr;
- info->ptr = lfe;
- }
- }
- /* compute column fixed value */
- s = 0.5 * (q->ub + q->lb);
- nint = floor(s + 0.5);
- if (fabs(s - nint) <= eps) s = nint;
- /* make column q fixed */
- q->lb = q->ub = s;
- return 1;
- }
- static int rcv_make_fixed(NPP *npp, void *_info)
- { /* recover column with almost identical bounds */
- struct make_fixed *info = _info;
- NPPLFE *lfe;
- double lambda;
- if (npp->sol == GLP_SOL)
- { if (npp->c_stat[info->q] == GLP_BS)
- npp->c_stat[info->q] = GLP_BS;
- else if (npp->c_stat[info->q] == GLP_NS)
- { /* compute multiplier for column q with formula (6) */
- lambda = info->c;
- for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
- lambda -= lfe->val * npp->r_pi[lfe->ref];
- /* assign status to non-basic column */
- if (lambda >= 0.0)
- npp->c_stat[info->q] = GLP_NL;
- else
- npp->c_stat[info->q] = GLP_NU;
- }
- else
- { npp_error();
- return 1;
- }
- }
- return 0;
- }
- /* eof */
|