glpnpp02.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  1. /* glpnpp02.c */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #include "glpnpp.h"
  24. /***********************************************************************
  25. * NAME
  26. *
  27. * npp_free_row - process free (unbounded) row
  28. *
  29. * SYNOPSIS
  30. *
  31. * #include "glpnpp.h"
  32. * void npp_free_row(NPP *npp, NPPROW *p);
  33. *
  34. * DESCRIPTION
  35. *
  36. * The routine npp_free_row processes row p, which is free (i.e. has
  37. * no finite bounds):
  38. *
  39. * -inf < sum a[p,j] x[j] < +inf. (1)
  40. * j
  41. *
  42. * PROBLEM TRANSFORMATION
  43. *
  44. * Constraint (1) cannot be active, so it is redundant and can be
  45. * removed from the original problem.
  46. *
  47. * Removing row p leads to removing a column of multiplier pi[p] for
  48. * this row in the dual system. Since row p has no bounds, pi[p] = 0,
  49. * so removing the column does not affect the dual solution.
  50. *
  51. * RECOVERING BASIC SOLUTION
  52. *
  53. * In solution to the original problem row p is inactive constraint,
  54. * so it is assigned status GLP_BS, and multiplier pi[p] is assigned
  55. * zero value.
  56. *
  57. * RECOVERING INTERIOR-POINT SOLUTION
  58. *
  59. * In solution to the original problem row p is inactive constraint,
  60. * so its multiplier pi[p] is assigned zero value.
  61. *
  62. * RECOVERING MIP SOLUTION
  63. *
  64. * None needed. */
  65. struct free_row
  66. { /* free (unbounded) row */
  67. int p;
  68. /* row reference number */
  69. };
  70. static int rcv_free_row(NPP *npp, void *info);
  71. void npp_free_row(NPP *npp, NPPROW *p)
  72. { /* process free (unbounded) row */
  73. struct free_row *info;
  74. /* the row must be free */
  75. xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
  76. /* create transformation stack entry */
  77. info = npp_push_tse(npp,
  78. rcv_free_row, sizeof(struct free_row));
  79. info->p = p->i;
  80. /* remove the row from the problem */
  81. npp_del_row(npp, p);
  82. return;
  83. }
  84. static int rcv_free_row(NPP *npp, void *_info)
  85. { /* recover free (unbounded) row */
  86. struct free_row *info = _info;
  87. if (npp->sol == GLP_SOL)
  88. npp->r_stat[info->p] = GLP_BS;
  89. if (npp->sol != GLP_MIP)
  90. npp->r_pi[info->p] = 0.0;
  91. return 0;
  92. }
  93. /***********************************************************************
  94. * NAME
  95. *
  96. * npp_geq_row - process row of 'not less than' type
  97. *
  98. * SYNOPSIS
  99. *
  100. * #include "glpnpp.h"
  101. * void npp_geq_row(NPP *npp, NPPROW *p);
  102. *
  103. * DESCRIPTION
  104. *
  105. * The routine npp_geq_row processes row p, which is 'not less than'
  106. * inequality constraint:
  107. *
  108. * L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
  109. * j
  110. *
  111. * where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
  112. *
  113. * PROBLEM TRANSFORMATION
  114. *
  115. * Constraint (1) can be replaced by equality constraint:
  116. *
  117. * sum a[p,j] x[j] - s = L[p], (2)
  118. * j
  119. *
  120. * where
  121. *
  122. * 0 <= s (<= U[p] - L[p]) (3)
  123. *
  124. * is a non-negative surplus variable.
  125. *
  126. * Since in the primal system there appears column s having the only
  127. * non-zero coefficient in row p, in the dual system there appears a
  128. * new row:
  129. *
  130. * (-1) pi[p] + lambda = 0, (4)
  131. *
  132. * where (-1) is coefficient of column s in row p, pi[p] is multiplier
  133. * of row p, lambda is multiplier of column q, 0 is coefficient of
  134. * column s in the objective row.
  135. *
  136. * RECOVERING BASIC SOLUTION
  137. *
  138. * Status of row p in solution to the original problem is determined
  139. * by its status and status of column q in solution to the transformed
  140. * problem as follows:
  141. *
  142. * +--------------------------------------+------------------+
  143. * | Transformed problem | Original problem |
  144. * +-----------------+--------------------+------------------+
  145. * | Status of row p | Status of column s | Status of row p |
  146. * +-----------------+--------------------+------------------+
  147. * | GLP_BS | GLP_BS | N/A |
  148. * | GLP_BS | GLP_NL | GLP_BS |
  149. * | GLP_BS | GLP_NU | GLP_BS |
  150. * | GLP_NS | GLP_BS | GLP_BS |
  151. * | GLP_NS | GLP_NL | GLP_NL |
  152. * | GLP_NS | GLP_NU | GLP_NU |
  153. * +-----------------+--------------------+------------------+
  154. *
  155. * Value of row multiplier pi[p] in solution to the original problem
  156. * is the same as in solution to the transformed problem.
  157. *
  158. * 1. In solution to the transformed problem row p and column q cannot
  159. * be basic at the same time; otherwise the basis matrix would have
  160. * two linear dependent columns: unity column of auxiliary variable
  161. * of row p and unity column of variable s.
  162. *
  163. * 2. Though in the transformed problem row p is equality constraint,
  164. * it may be basic due to primal degenerate solution.
  165. *
  166. * RECOVERING INTERIOR-POINT SOLUTION
  167. *
  168. * Value of row multiplier pi[p] in solution to the original problem
  169. * is the same as in solution to the transformed problem.
  170. *
  171. * RECOVERING MIP SOLUTION
  172. *
  173. * None needed. */
  174. struct ineq_row
  175. { /* inequality constraint row */
  176. int p;
  177. /* row reference number */
  178. int s;
  179. /* column reference number for slack/surplus variable */
  180. };
  181. static int rcv_geq_row(NPP *npp, void *info);
  182. void npp_geq_row(NPP *npp, NPPROW *p)
  183. { /* process row of 'not less than' type */
  184. struct ineq_row *info;
  185. NPPCOL *s;
  186. /* the row must have lower bound */
  187. xassert(p->lb != -DBL_MAX);
  188. xassert(p->lb < p->ub);
  189. /* create column for surplus variable */
  190. s = npp_add_col(npp);
  191. s->lb = 0.0;
  192. s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
  193. /* and add it to the transformed problem */
  194. npp_add_aij(npp, p, s, -1.0);
  195. /* create transformation stack entry */
  196. info = npp_push_tse(npp,
  197. rcv_geq_row, sizeof(struct ineq_row));
  198. info->p = p->i;
  199. info->s = s->j;
  200. /* replace the row by equality constraint */
  201. p->ub = p->lb;
  202. return;
  203. }
  204. static int rcv_geq_row(NPP *npp, void *_info)
  205. { /* recover row of 'not less than' type */
  206. struct ineq_row *info = _info;
  207. if (npp->sol == GLP_SOL)
  208. { if (npp->r_stat[info->p] == GLP_BS)
  209. { if (npp->c_stat[info->s] == GLP_BS)
  210. { npp_error();
  211. return 1;
  212. }
  213. else if (npp->c_stat[info->s] == GLP_NL ||
  214. npp->c_stat[info->s] == GLP_NU)
  215. npp->r_stat[info->p] = GLP_BS;
  216. else
  217. { npp_error();
  218. return 1;
  219. }
  220. }
  221. else if (npp->r_stat[info->p] == GLP_NS)
  222. { if (npp->c_stat[info->s] == GLP_BS)
  223. npp->r_stat[info->p] = GLP_BS;
  224. else if (npp->c_stat[info->s] == GLP_NL)
  225. npp->r_stat[info->p] = GLP_NL;
  226. else if (npp->c_stat[info->s] == GLP_NU)
  227. npp->r_stat[info->p] = GLP_NU;
  228. else
  229. { npp_error();
  230. return 1;
  231. }
  232. }
  233. else
  234. { npp_error();
  235. return 1;
  236. }
  237. }
  238. return 0;
  239. }
  240. /***********************************************************************
  241. * NAME
  242. *
  243. * npp_leq_row - process row of 'not greater than' type
  244. *
  245. * SYNOPSIS
  246. *
  247. * #include "glpnpp.h"
  248. * void npp_leq_row(NPP *npp, NPPROW *p);
  249. *
  250. * DESCRIPTION
  251. *
  252. * The routine npp_leq_row processes row p, which is 'not greater than'
  253. * inequality constraint:
  254. *
  255. * (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
  256. * j
  257. *
  258. * where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
  259. *
  260. * PROBLEM TRANSFORMATION
  261. *
  262. * Constraint (1) can be replaced by equality constraint:
  263. *
  264. * sum a[p,j] x[j] + s = L[p], (2)
  265. * j
  266. *
  267. * where
  268. *
  269. * 0 <= s (<= U[p] - L[p]) (3)
  270. *
  271. * is a non-negative slack variable.
  272. *
  273. * Since in the primal system there appears column s having the only
  274. * non-zero coefficient in row p, in the dual system there appears a
  275. * new row:
  276. *
  277. * (+1) pi[p] + lambda = 0, (4)
  278. *
  279. * where (+1) is coefficient of column s in row p, pi[p] is multiplier
  280. * of row p, lambda is multiplier of column q, 0 is coefficient of
  281. * column s in the objective row.
  282. *
  283. * RECOVERING BASIC SOLUTION
  284. *
  285. * Status of row p in solution to the original problem is determined
  286. * by its status and status of column q in solution to the transformed
  287. * problem as follows:
  288. *
  289. * +--------------------------------------+------------------+
  290. * | Transformed problem | Original problem |
  291. * +-----------------+--------------------+------------------+
  292. * | Status of row p | Status of column s | Status of row p |
  293. * +-----------------+--------------------+------------------+
  294. * | GLP_BS | GLP_BS | N/A |
  295. * | GLP_BS | GLP_NL | GLP_BS |
  296. * | GLP_BS | GLP_NU | GLP_BS |
  297. * | GLP_NS | GLP_BS | GLP_BS |
  298. * | GLP_NS | GLP_NL | GLP_NU |
  299. * | GLP_NS | GLP_NU | GLP_NL |
  300. * +-----------------+--------------------+------------------+
  301. *
  302. * Value of row multiplier pi[p] in solution to the original problem
  303. * is the same as in solution to the transformed problem.
  304. *
  305. * 1. In solution to the transformed problem row p and column q cannot
  306. * be basic at the same time; otherwise the basis matrix would have
  307. * two linear dependent columns: unity column of auxiliary variable
  308. * of row p and unity column of variable s.
  309. *
  310. * 2. Though in the transformed problem row p is equality constraint,
  311. * it may be basic due to primal degeneracy.
  312. *
  313. * RECOVERING INTERIOR-POINT SOLUTION
  314. *
  315. * Value of row multiplier pi[p] in solution to the original problem
  316. * is the same as in solution to the transformed problem.
  317. *
  318. * RECOVERING MIP SOLUTION
  319. *
  320. * None needed. */
  321. static int rcv_leq_row(NPP *npp, void *info);
  322. void npp_leq_row(NPP *npp, NPPROW *p)
  323. { /* process row of 'not greater than' type */
  324. struct ineq_row *info;
  325. NPPCOL *s;
  326. /* the row must have upper bound */
  327. xassert(p->ub != +DBL_MAX);
  328. xassert(p->lb < p->ub);
  329. /* create column for slack variable */
  330. s = npp_add_col(npp);
  331. s->lb = 0.0;
  332. s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
  333. /* and add it to the transformed problem */
  334. npp_add_aij(npp, p, s, +1.0);
  335. /* create transformation stack entry */
  336. info = npp_push_tse(npp,
  337. rcv_leq_row, sizeof(struct ineq_row));
  338. info->p = p->i;
  339. info->s = s->j;
  340. /* replace the row by equality constraint */
  341. p->lb = p->ub;
  342. return;
  343. }
  344. static int rcv_leq_row(NPP *npp, void *_info)
  345. { /* recover row of 'not greater than' type */
  346. struct ineq_row *info = _info;
  347. if (npp->sol == GLP_SOL)
  348. { if (npp->r_stat[info->p] == GLP_BS)
  349. { if (npp->c_stat[info->s] == GLP_BS)
  350. { npp_error();
  351. return 1;
  352. }
  353. else if (npp->c_stat[info->s] == GLP_NL ||
  354. npp->c_stat[info->s] == GLP_NU)
  355. npp->r_stat[info->p] = GLP_BS;
  356. else
  357. { npp_error();
  358. return 1;
  359. }
  360. }
  361. else if (npp->r_stat[info->p] == GLP_NS)
  362. { if (npp->c_stat[info->s] == GLP_BS)
  363. npp->r_stat[info->p] = GLP_BS;
  364. else if (npp->c_stat[info->s] == GLP_NL)
  365. npp->r_stat[info->p] = GLP_NU;
  366. else if (npp->c_stat[info->s] == GLP_NU)
  367. npp->r_stat[info->p] = GLP_NL;
  368. else
  369. { npp_error();
  370. return 1;
  371. }
  372. }
  373. else
  374. { npp_error();
  375. return 1;
  376. }
  377. }
  378. return 0;
  379. }
  380. /***********************************************************************
  381. * NAME
  382. *
  383. * npp_free_col - process free (unbounded) column
  384. *
  385. * SYNOPSIS
  386. *
  387. * #include "glpnpp.h"
  388. * void npp_free_col(NPP *npp, NPPCOL *q);
  389. *
  390. * DESCRIPTION
  391. *
  392. * The routine npp_free_col processes column q, which is free (i.e. has
  393. * no finite bounds):
  394. *
  395. * -oo < x[q] < +oo. (1)
  396. *
  397. * PROBLEM TRANSFORMATION
  398. *
  399. * Free (unbounded) variable can be replaced by the difference of two
  400. * non-negative variables:
  401. *
  402. * x[q] = s' - s'', s', s'' >= 0. (2)
  403. *
  404. * Assuming that in the transformed problem x[q] becomes s',
  405. * transformation (2) causes new column s'' to appear, which differs
  406. * from column s' only in the sign of coefficients in constraint and
  407. * objective rows. Thus, if in the dual system the following row
  408. * corresponds to column s':
  409. *
  410. * sum a[i,q] pi[i] + lambda' = c[q], (3)
  411. * i
  412. *
  413. * the row which corresponds to column s'' is the following:
  414. *
  415. * sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
  416. * i
  417. *
  418. * Then from (3) and (4) it follows that:
  419. *
  420. * lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
  421. *
  422. * where lambda' and lambda'' are multipliers for columns s' and s'',
  423. * resp.
  424. *
  425. * RECOVERING BASIC SOLUTION
  426. *
  427. * With respect to (5) status of column q in solution to the original
  428. * problem is determined by statuses of columns s' and s'' in solution
  429. * to the transformed problem as follows:
  430. *
  431. * +--------------------------------------+------------------+
  432. * | Transformed problem | Original problem |
  433. * +------------------+-------------------+------------------+
  434. * | Status of col s' | Status of col s'' | Status of col q |
  435. * +------------------+-------------------+------------------+
  436. * | GLP_BS | GLP_BS | N/A |
  437. * | GLP_BS | GLP_NL | GLP_BS |
  438. * | GLP_NL | GLP_BS | GLP_BS |
  439. * | GLP_NL | GLP_NL | GLP_NF |
  440. * +------------------+-------------------+------------------+
  441. *
  442. * Value of column q is computed with formula (2).
  443. *
  444. * 1. In solution to the transformed problem columns s' and s'' cannot
  445. * be basic at the same time, because they differ only in the sign,
  446. * hence, are linear dependent.
  447. *
  448. * 2. Though column q is free, it can be non-basic due to dual
  449. * degeneracy.
  450. *
  451. * 3. If column q is integral, columns s' and s'' are also integral.
  452. *
  453. * RECOVERING INTERIOR-POINT SOLUTION
  454. *
  455. * Value of column q is computed with formula (2).
  456. *
  457. * RECOVERING MIP SOLUTION
  458. *
  459. * Value of column q is computed with formula (2). */
  460. struct free_col
  461. { /* free (unbounded) column */
  462. int q;
  463. /* column reference number for variables x[q] and s' */
  464. int s;
  465. /* column reference number for variable s'' */
  466. };
  467. static int rcv_free_col(NPP *npp, void *info);
  468. void npp_free_col(NPP *npp, NPPCOL *q)
  469. { /* process free (unbounded) column */
  470. struct free_col *info;
  471. NPPCOL *s;
  472. NPPAIJ *aij;
  473. /* the column must be free */
  474. xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
  475. /* variable x[q] becomes s' */
  476. q->lb = 0.0, q->ub = +DBL_MAX;
  477. /* create variable s'' */
  478. s = npp_add_col(npp);
  479. s->is_int = q->is_int;
  480. s->lb = 0.0, s->ub = +DBL_MAX;
  481. /* duplicate objective coefficient */
  482. s->coef = -q->coef;
  483. /* duplicate column of the constraint matrix */
  484. for (aij = q->ptr; aij != NULL; aij = aij->c_next)
  485. npp_add_aij(npp, aij->row, s, -aij->val);
  486. /* create transformation stack entry */
  487. info = npp_push_tse(npp,
  488. rcv_free_col, sizeof(struct free_col));
  489. info->q = q->j;
  490. info->s = s->j;
  491. return;
  492. }
  493. static int rcv_free_col(NPP *npp, void *_info)
  494. { /* recover free (unbounded) column */
  495. struct free_col *info = _info;
  496. if (npp->sol == GLP_SOL)
  497. { if (npp->c_stat[info->q] == GLP_BS)
  498. { if (npp->c_stat[info->s] == GLP_BS)
  499. { npp_error();
  500. return 1;
  501. }
  502. else if (npp->c_stat[info->s] == GLP_NL)
  503. npp->c_stat[info->q] = GLP_BS;
  504. else
  505. { npp_error();
  506. return -1;
  507. }
  508. }
  509. else if (npp->c_stat[info->q] == GLP_NL)
  510. { if (npp->c_stat[info->s] == GLP_BS)
  511. npp->c_stat[info->q] = GLP_BS;
  512. else if (npp->c_stat[info->s] == GLP_NL)
  513. npp->c_stat[info->q] = GLP_NF;
  514. else
  515. { npp_error();
  516. return -1;
  517. }
  518. }
  519. else
  520. { npp_error();
  521. return -1;
  522. }
  523. }
  524. /* compute value of x[q] with formula (2) */
  525. npp->c_value[info->q] -= npp->c_value[info->s];
  526. return 0;
  527. }
  528. /***********************************************************************
  529. * NAME
  530. *
  531. * npp_lbnd_col - process column with (non-zero) lower bound
  532. *
  533. * SYNOPSIS
  534. *
  535. * #include "glpnpp.h"
  536. * void npp_lbnd_col(NPP *npp, NPPCOL *q);
  537. *
  538. * DESCRIPTION
  539. *
  540. * The routine npp_lbnd_col processes column q, which has (non-zero)
  541. * lower bound:
  542. *
  543. * l[q] <= x[q] (<= u[q]), (1)
  544. *
  545. * where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
  546. *
  547. * PROBLEM TRANSFORMATION
  548. *
  549. * Column q can be replaced as follows:
  550. *
  551. * x[q] = l[q] + s, (2)
  552. *
  553. * where
  554. *
  555. * 0 <= s (<= u[q] - l[q]) (3)
  556. *
  557. * is a non-negative variable.
  558. *
  559. * Substituting x[q] from (2) into the objective row, we have:
  560. *
  561. * z = sum c[j] x[j] + c0 =
  562. * j
  563. *
  564. * = sum c[j] x[j] + c[q] x[q] + c0 =
  565. * j!=q
  566. *
  567. * = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
  568. * j!=q
  569. *
  570. * = sum c[j] x[j] + c[q] s + c~0,
  571. *
  572. * where
  573. *
  574. * c~0 = c0 + c[q] l[q] (4)
  575. *
  576. * is the constant term of the objective in the transformed problem.
  577. * Similarly, substituting x[q] into constraint row i, we have:
  578. *
  579. * L[i] <= sum a[i,j] x[j] <= U[i] ==>
  580. * j
  581. *
  582. * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
  583. * j!=q
  584. *
  585. * L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
  586. * j!=q
  587. *
  588. * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
  589. * j!=q
  590. *
  591. * where
  592. *
  593. * L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
  594. *
  595. * are lower and upper bounds of row i in the transformed problem,
  596. * resp.
  597. *
  598. * Transformation (2) does not affect the dual system.
  599. *
  600. * RECOVERING BASIC SOLUTION
  601. *
  602. * Status of column q in solution to the original problem is the same
  603. * as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
  604. * Value of column q is computed with formula (2).
  605. *
  606. * RECOVERING INTERIOR-POINT SOLUTION
  607. *
  608. * Value of column q is computed with formula (2).
  609. *
  610. * RECOVERING MIP SOLUTION
  611. *
  612. * Value of column q is computed with formula (2). */
  613. struct bnd_col
  614. { /* bounded column */
  615. int q;
  616. /* column reference number for variables x[q] and s */
  617. double bnd;
  618. /* lower/upper bound l[q] or u[q] */
  619. };
  620. static int rcv_lbnd_col(NPP *npp, void *info);
  621. void npp_lbnd_col(NPP *npp, NPPCOL *q)
  622. { /* process column with (non-zero) lower bound */
  623. struct bnd_col *info;
  624. NPPROW *i;
  625. NPPAIJ *aij;
  626. /* the column must have non-zero lower bound */
  627. xassert(q->lb != 0.0);
  628. xassert(q->lb != -DBL_MAX);
  629. xassert(q->lb < q->ub);
  630. /* create transformation stack entry */
  631. info = npp_push_tse(npp,
  632. rcv_lbnd_col, sizeof(struct bnd_col));
  633. info->q = q->j;
  634. info->bnd = q->lb;
  635. /* substitute x[q] into objective row */
  636. npp->c0 += q->coef * q->lb;
  637. /* substitute x[q] into constraint rows */
  638. for (aij = q->ptr; aij != NULL; aij = aij->c_next)
  639. { i = aij->row;
  640. if (i->lb == i->ub)
  641. i->ub = (i->lb -= aij->val * q->lb);
  642. else
  643. { if (i->lb != -DBL_MAX)
  644. i->lb -= aij->val * q->lb;
  645. if (i->ub != +DBL_MAX)
  646. i->ub -= aij->val * q->lb;
  647. }
  648. }
  649. /* column x[q] becomes column s */
  650. if (q->ub != +DBL_MAX)
  651. q->ub -= q->lb;
  652. q->lb = 0.0;
  653. return;
  654. }
  655. static int rcv_lbnd_col(NPP *npp, void *_info)
  656. { /* recover column with (non-zero) lower bound */
  657. struct bnd_col *info = _info;
  658. if (npp->sol == GLP_SOL)
  659. { if (npp->c_stat[info->q] == GLP_BS ||
  660. npp->c_stat[info->q] == GLP_NL ||
  661. npp->c_stat[info->q] == GLP_NU)
  662. npp->c_stat[info->q] = npp->c_stat[info->q];
  663. else
  664. { npp_error();
  665. return 1;
  666. }
  667. }
  668. /* compute value of x[q] with formula (2) */
  669. npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
  670. return 0;
  671. }
  672. /***********************************************************************
  673. * NAME
  674. *
  675. * npp_ubnd_col - process column with upper bound
  676. *
  677. * SYNOPSIS
  678. *
  679. * #include "glpnpp.h"
  680. * void npp_ubnd_col(NPP *npp, NPPCOL *q);
  681. *
  682. * DESCRIPTION
  683. *
  684. * The routine npp_ubnd_col processes column q, which has upper bound:
  685. *
  686. * (l[q] <=) x[q] <= u[q], (1)
  687. *
  688. * where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
  689. *
  690. * PROBLEM TRANSFORMATION
  691. *
  692. * Column q can be replaced as follows:
  693. *
  694. * x[q] = u[q] - s, (2)
  695. *
  696. * where
  697. *
  698. * 0 <= s (<= u[q] - l[q]) (3)
  699. *
  700. * is a non-negative variable.
  701. *
  702. * Substituting x[q] from (2) into the objective row, we have:
  703. *
  704. * z = sum c[j] x[j] + c0 =
  705. * j
  706. *
  707. * = sum c[j] x[j] + c[q] x[q] + c0 =
  708. * j!=q
  709. *
  710. * = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
  711. * j!=q
  712. *
  713. * = sum c[j] x[j] - c[q] s + c~0,
  714. *
  715. * where
  716. *
  717. * c~0 = c0 + c[q] u[q] (4)
  718. *
  719. * is the constant term of the objective in the transformed problem.
  720. * Similarly, substituting x[q] into constraint row i, we have:
  721. *
  722. * L[i] <= sum a[i,j] x[j] <= U[i] ==>
  723. * j
  724. *
  725. * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
  726. * j!=q
  727. *
  728. * L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
  729. * j!=q
  730. *
  731. * L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
  732. * j!=q
  733. *
  734. * where
  735. *
  736. * L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
  737. *
  738. * are lower and upper bounds of row i in the transformed problem,
  739. * resp.
  740. *
  741. * Note that in the transformed problem coefficients c[q] and a[i,q]
  742. * change their sign. Thus, the row of the dual system corresponding to
  743. * column q:
  744. *
  745. * sum a[i,q] pi[i] + lambda[q] = c[q] (6)
  746. * i
  747. *
  748. * in the transformed problem becomes the following:
  749. *
  750. * sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
  751. * i
  752. *
  753. * Therefore:
  754. *
  755. * lambda[q] = - lambda[s], (8)
  756. *
  757. * where lambda[q] is multiplier for column q, lambda[s] is multiplier
  758. * for column s.
  759. *
  760. * RECOVERING BASIC SOLUTION
  761. *
  762. * With respect to (8) status of column q in solution to the original
  763. * problem is determined by status of column s in solution to the
  764. * transformed problem as follows:
  765. *
  766. * +-----------------------+--------------------+
  767. * | Status of column s | Status of column q |
  768. * | (transformed problem) | (original problem) |
  769. * +-----------------------+--------------------+
  770. * | GLP_BS | GLP_BS |
  771. * | GLP_NL | GLP_NU |
  772. * | GLP_NU | GLP_NL |
  773. * +-----------------------+--------------------+
  774. *
  775. * Value of column q is computed with formula (2).
  776. *
  777. * RECOVERING INTERIOR-POINT SOLUTION
  778. *
  779. * Value of column q is computed with formula (2).
  780. *
  781. * RECOVERING MIP SOLUTION
  782. *
  783. * Value of column q is computed with formula (2). */
  784. static int rcv_ubnd_col(NPP *npp, void *info);
  785. void npp_ubnd_col(NPP *npp, NPPCOL *q)
  786. { /* process column with upper bound */
  787. struct bnd_col *info;
  788. NPPROW *i;
  789. NPPAIJ *aij;
  790. /* the column must have upper bound */
  791. xassert(q->ub != +DBL_MAX);
  792. xassert(q->lb < q->ub);
  793. /* create transformation stack entry */
  794. info = npp_push_tse(npp,
  795. rcv_ubnd_col, sizeof(struct bnd_col));
  796. info->q = q->j;
  797. info->bnd = q->ub;
  798. /* substitute x[q] into objective row */
  799. npp->c0 += q->coef * q->ub;
  800. q->coef = -q->coef;
  801. /* substitute x[q] into constraint rows */
  802. for (aij = q->ptr; aij != NULL; aij = aij->c_next)
  803. { i = aij->row;
  804. if (i->lb == i->ub)
  805. i->ub = (i->lb -= aij->val * q->ub);
  806. else
  807. { if (i->lb != -DBL_MAX)
  808. i->lb -= aij->val * q->ub;
  809. if (i->ub != +DBL_MAX)
  810. i->ub -= aij->val * q->ub;
  811. }
  812. aij->val = -aij->val;
  813. }
  814. /* column x[q] becomes column s */
  815. if (q->lb != -DBL_MAX)
  816. q->ub -= q->lb;
  817. else
  818. q->ub = +DBL_MAX;
  819. q->lb = 0.0;
  820. return;
  821. }
  822. static int rcv_ubnd_col(NPP *npp, void *_info)
  823. { /* recover column with upper bound */
  824. struct bnd_col *info = _info;
  825. if (npp->sol == GLP_BS)
  826. { if (npp->c_stat[info->q] == GLP_BS)
  827. npp->c_stat[info->q] = GLP_BS;
  828. else if (npp->c_stat[info->q] == GLP_NL)
  829. npp->c_stat[info->q] = GLP_NU;
  830. else if (npp->c_stat[info->q] == GLP_NU)
  831. npp->c_stat[info->q] = GLP_NL;
  832. else
  833. { npp_error();
  834. return 1;
  835. }
  836. }
  837. /* compute value of x[q] with formula (2) */
  838. npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
  839. return 0;
  840. }
  841. /***********************************************************************
  842. * NAME
  843. *
  844. * npp_dbnd_col - process non-negative column with upper bound
  845. *
  846. * SYNOPSIS
  847. *
  848. * #include "glpnpp.h"
  849. * void npp_dbnd_col(NPP *npp, NPPCOL *q);
  850. *
  851. * DESCRIPTION
  852. *
  853. * The routine npp_dbnd_col processes column q, which is non-negative
  854. * and has upper bound:
  855. *
  856. * 0 <= x[q] <= u[q], (1)
  857. *
  858. * where u[q] > 0.
  859. *
  860. * PROBLEM TRANSFORMATION
  861. *
  862. * Upper bound of column q can be replaced by the following equality
  863. * constraint:
  864. *
  865. * x[q] + s = u[q], (2)
  866. *
  867. * where s >= 0 is a non-negative complement variable.
  868. *
  869. * Since in the primal system along with new row (2) there appears a
  870. * new column s having the only non-zero coefficient in this row, in
  871. * the dual system there appears a new row:
  872. *
  873. * (+1)pi + lambda[s] = 0, (3)
  874. *
  875. * where (+1) is coefficient at column s in row (2), pi is multiplier
  876. * for row (2), lambda[s] is multiplier for column s, 0 is coefficient
  877. * at column s in the objective row.
  878. *
  879. * RECOVERING BASIC SOLUTION
  880. *
  881. * Status of column q in solution to the original problem is determined
  882. * by its status and status of column s in solution to the transformed
  883. * problem as follows:
  884. *
  885. * +-----------------------------------+------------------+
  886. * | Transformed problem | Original problem |
  887. * +-----------------+-----------------+------------------+
  888. * | Status of col q | Status of col s | Status of col q |
  889. * +-----------------+-----------------+------------------+
  890. * | GLP_BS | GLP_BS | GLP_BS |
  891. * | GLP_BS | GLP_NL | GLP_NU |
  892. * | GLP_NL | GLP_BS | GLP_NL |
  893. * | GLP_NL | GLP_NL | GLP_NL (*) |
  894. * +-----------------+-----------------+------------------+
  895. *
  896. * Value of column q in solution to the original problem is the same as
  897. * in solution to the transformed problem.
  898. *
  899. * 1. Formally, in solution to the transformed problem columns q and s
  900. * cannot be non-basic at the same time, since the constraint (2)
  901. * would be violated. However, if u[q] is close to zero, violation
  902. * may be less than a working precision even if both columns q and s
  903. * are non-basic. In this degenerate case row (2) can be only basic,
  904. * i.e. non-active constraint (otherwise corresponding row of the
  905. * basis matrix would be zero). This allows to pivot out auxiliary
  906. * variable and pivot in column s, in which case the row becomes
  907. * active while column s becomes basic.
  908. *
  909. * 2. If column q is integral, column s is also integral.
  910. *
  911. * RECOVERING INTERIOR-POINT SOLUTION
  912. *
  913. * Value of column q in solution to the original problem is the same as
  914. * in solution to the transformed problem.
  915. *
  916. * RECOVERING MIP SOLUTION
  917. *
  918. * Value of column q in solution to the original problem is the same as
  919. * in solution to the transformed problem. */
  920. struct dbnd_col
  921. { /* double-bounded column */
  922. int q;
  923. /* column reference number for variable x[q] */
  924. int s;
  925. /* column reference number for complement variable s */
  926. };
  927. static int rcv_dbnd_col(NPP *npp, void *info);
  928. void npp_dbnd_col(NPP *npp, NPPCOL *q)
  929. { /* process non-negative column with upper bound */
  930. struct dbnd_col *info;
  931. NPPROW *p;
  932. NPPCOL *s;
  933. /* the column must be non-negative with upper bound */
  934. xassert(q->lb == 0.0);
  935. xassert(q->ub > 0.0);
  936. xassert(q->ub != +DBL_MAX);
  937. /* create variable s */
  938. s = npp_add_col(npp);
  939. s->is_int = q->is_int;
  940. s->lb = 0.0, s->ub = +DBL_MAX;
  941. /* create equality constraint (2) */
  942. p = npp_add_row(npp);
  943. p->lb = p->ub = q->ub;
  944. npp_add_aij(npp, p, q, +1.0);
  945. npp_add_aij(npp, p, s, +1.0);
  946. /* create transformation stack entry */
  947. info = npp_push_tse(npp,
  948. rcv_dbnd_col, sizeof(struct dbnd_col));
  949. info->q = q->j;
  950. info->s = s->j;
  951. /* remove upper bound of x[q] */
  952. q->ub = +DBL_MAX;
  953. return;
  954. }
  955. static int rcv_dbnd_col(NPP *npp, void *_info)
  956. { /* recover non-negative column with upper bound */
  957. struct dbnd_col *info = _info;
  958. if (npp->sol == GLP_BS)
  959. { if (npp->c_stat[info->q] == GLP_BS)
  960. { if (npp->c_stat[info->s] == GLP_BS)
  961. npp->c_stat[info->q] = GLP_BS;
  962. else if (npp->c_stat[info->s] == GLP_NL)
  963. npp->c_stat[info->q] = GLP_NU;
  964. else
  965. { npp_error();
  966. return 1;
  967. }
  968. }
  969. else if (npp->c_stat[info->q] == GLP_NL)
  970. { if (npp->c_stat[info->s] == GLP_BS ||
  971. npp->c_stat[info->s] == GLP_NL)
  972. npp->c_stat[info->q] = GLP_NL;
  973. else
  974. { npp_error();
  975. return 1;
  976. }
  977. }
  978. else
  979. { npp_error();
  980. return 1;
  981. }
  982. }
  983. return 0;
  984. }
  985. /***********************************************************************
  986. * NAME
  987. *
  988. * npp_fixed_col - process fixed column
  989. *
  990. * SYNOPSIS
  991. *
  992. * #include "glpnpp.h"
  993. * void npp_fixed_col(NPP *npp, NPPCOL *q);
  994. *
  995. * DESCRIPTION
  996. *
  997. * The routine npp_fixed_col processes column q, which is fixed:
  998. *
  999. * x[q] = s[q], (1)
  1000. *
  1001. * where s[q] is a fixed column value.
  1002. *
  1003. * PROBLEM TRANSFORMATION
  1004. *
  1005. * The value of a fixed column can be substituted into the objective
  1006. * and constraint rows that allows removing the column from the problem.
  1007. *
  1008. * Substituting x[q] = s[q] into the objective row, we have:
  1009. *
  1010. * z = sum c[j] x[j] + c0 =
  1011. * j
  1012. *
  1013. * = sum c[j] x[j] + c[q] x[q] + c0 =
  1014. * j!=q
  1015. *
  1016. * = sum c[j] x[j] + c[q] s[q] + c0 =
  1017. * j!=q
  1018. *
  1019. * = sum c[j] x[j] + c~0,
  1020. * j!=q
  1021. *
  1022. * where
  1023. *
  1024. * c~0 = c0 + c[q] s[q] (2)
  1025. *
  1026. * is the constant term of the objective in the transformed problem.
  1027. * Similarly, substituting x[q] = s[q] into constraint row i, we have:
  1028. *
  1029. * L[i] <= sum a[i,j] x[j] <= U[i] ==>
  1030. * j
  1031. *
  1032. * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
  1033. * j!=q
  1034. *
  1035. * L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
  1036. * j!=q
  1037. *
  1038. * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
  1039. * j!=q
  1040. *
  1041. * where
  1042. *
  1043. * L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
  1044. *
  1045. * are lower and upper bounds of row i in the transformed problem,
  1046. * resp.
  1047. *
  1048. * RECOVERING BASIC SOLUTION
  1049. *
  1050. * Column q is assigned status GLP_NS and its value is assigned s[q].
  1051. *
  1052. * RECOVERING INTERIOR-POINT SOLUTION
  1053. *
  1054. * Value of column q is assigned s[q].
  1055. *
  1056. * RECOVERING MIP SOLUTION
  1057. *
  1058. * Value of column q is assigned s[q]. */
  1059. struct fixed_col
  1060. { /* fixed column */
  1061. int q;
  1062. /* column reference number for variable x[q] */
  1063. double s;
  1064. /* value, at which x[q] is fixed */
  1065. };
  1066. static int rcv_fixed_col(NPP *npp, void *info);
  1067. void npp_fixed_col(NPP *npp, NPPCOL *q)
  1068. { /* process fixed column */
  1069. struct fixed_col *info;
  1070. NPPROW *i;
  1071. NPPAIJ *aij;
  1072. /* the column must be fixed */
  1073. xassert(q->lb == q->ub);
  1074. /* create transformation stack entry */
  1075. info = npp_push_tse(npp,
  1076. rcv_fixed_col, sizeof(struct fixed_col));
  1077. info->q = q->j;
  1078. info->s = q->lb;
  1079. /* substitute x[q] = s[q] into objective row */
  1080. npp->c0 += q->coef * q->lb;
  1081. /* substitute x[q] = s[q] into constraint rows */
  1082. for (aij = q->ptr; aij != NULL; aij = aij->c_next)
  1083. { i = aij->row;
  1084. if (i->lb == i->ub)
  1085. i->ub = (i->lb -= aij->val * q->lb);
  1086. else
  1087. { if (i->lb != -DBL_MAX)
  1088. i->lb -= aij->val * q->lb;
  1089. if (i->ub != +DBL_MAX)
  1090. i->ub -= aij->val * q->lb;
  1091. }
  1092. }
  1093. /* remove the column from the problem */
  1094. npp_del_col(npp, q);
  1095. return;
  1096. }
  1097. static int rcv_fixed_col(NPP *npp, void *_info)
  1098. { /* recover fixed column */
  1099. struct fixed_col *info = _info;
  1100. if (npp->sol == GLP_SOL)
  1101. npp->c_stat[info->q] = GLP_NS;
  1102. npp->c_value[info->q] = info->s;
  1103. return 0;
  1104. }
  1105. /***********************************************************************
  1106. * NAME
  1107. *
  1108. * npp_make_equality - process row with almost identical bounds
  1109. *
  1110. * SYNOPSIS
  1111. *
  1112. * #include "glpnpp.h"
  1113. * int npp_make_equality(NPP *npp, NPPROW *p);
  1114. *
  1115. * DESCRIPTION
  1116. *
  1117. * The routine npp_make_equality processes row p:
  1118. *
  1119. * L[p] <= sum a[p,j] x[j] <= U[p], (1)
  1120. * j
  1121. *
  1122. * where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
  1123. * constraint.
  1124. *
  1125. * RETURNS
  1126. *
  1127. * 0 - row bounds have not been changed;
  1128. *
  1129. * 1 - row has been replaced by equality constraint.
  1130. *
  1131. * PROBLEM TRANSFORMATION
  1132. *
  1133. * If bounds of row (1) are very close to each other:
  1134. *
  1135. * U[p] - L[p] <= eps, (2)
  1136. *
  1137. * where eps is an absolute tolerance for row value, the row can be
  1138. * replaced by the following almost equivalent equiality constraint:
  1139. *
  1140. * sum a[p,j] x[j] = b, (3)
  1141. * j
  1142. *
  1143. * where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
  1144. * to be very close to its nearest integer:
  1145. *
  1146. * |b - floor(b + 0.5)| <= eps, (4)
  1147. *
  1148. * it is reasonable to use this nearest integer as the right-hand side.
  1149. *
  1150. * RECOVERING BASIC SOLUTION
  1151. *
  1152. * Status of row p in solution to the original problem is determined
  1153. * by its status and the sign of its multiplier pi[p] in solution to
  1154. * the transformed problem as follows:
  1155. *
  1156. * +-----------------------+---------+--------------------+
  1157. * | Status of row p | Sign of | Status of row p |
  1158. * | (transformed problem) | pi[p] | (original problem) |
  1159. * +-----------------------+---------+--------------------+
  1160. * | GLP_BS | + / - | GLP_BS |
  1161. * | GLP_NS | + | GLP_NL |
  1162. * | GLP_NS | - | GLP_NU |
  1163. * +-----------------------+---------+--------------------+
  1164. *
  1165. * Value of row multiplier pi[p] in solution to the original problem is
  1166. * the same as in solution to the transformed problem.
  1167. *
  1168. * RECOVERING INTERIOR POINT SOLUTION
  1169. *
  1170. * Value of row multiplier pi[p] in solution to the original problem is
  1171. * the same as in solution to the transformed problem.
  1172. *
  1173. * RECOVERING MIP SOLUTION
  1174. *
  1175. * None needed. */
  1176. struct make_equality
  1177. { /* row with almost identical bounds */
  1178. int p;
  1179. /* row reference number */
  1180. };
  1181. static int rcv_make_equality(NPP *npp, void *info);
  1182. int npp_make_equality(NPP *npp, NPPROW *p)
  1183. { /* process row with almost identical bounds */
  1184. struct make_equality *info;
  1185. double b, eps, nint;
  1186. /* the row must be double-sided inequality */
  1187. xassert(p->lb != -DBL_MAX);
  1188. xassert(p->ub != +DBL_MAX);
  1189. xassert(p->lb < p->ub);
  1190. /* check row bounds */
  1191. eps = 1e-9 + 1e-12 * fabs(p->lb);
  1192. if (p->ub - p->lb > eps) return 0;
  1193. /* row bounds are very close to each other */
  1194. /* create transformation stack entry */
  1195. info = npp_push_tse(npp,
  1196. rcv_make_equality, sizeof(struct make_equality));
  1197. info->p = p->i;
  1198. /* compute right-hand side */
  1199. b = 0.5 * (p->ub + p->lb);
  1200. nint = floor(b + 0.5);
  1201. if (fabs(b - nint) <= eps) b = nint;
  1202. /* replace row p by almost equivalent equality constraint */
  1203. p->lb = p->ub = b;
  1204. return 1;
  1205. }
  1206. int rcv_make_equality(NPP *npp, void *_info)
  1207. { /* recover row with almost identical bounds */
  1208. struct make_equality *info = _info;
  1209. if (npp->sol == GLP_SOL)
  1210. { if (npp->r_stat[info->p] == GLP_BS)
  1211. npp->r_stat[info->p] = GLP_BS;
  1212. else if (npp->r_stat[info->p] == GLP_NS)
  1213. { if (npp->r_pi[info->p] >= 0.0)
  1214. npp->r_stat[info->p] = GLP_NL;
  1215. else
  1216. npp->r_stat[info->p] = GLP_NU;
  1217. }
  1218. else
  1219. { npp_error();
  1220. return 1;
  1221. }
  1222. }
  1223. return 0;
  1224. }
  1225. /***********************************************************************
  1226. * NAME
  1227. *
  1228. * npp_make_fixed - process column with almost identical bounds
  1229. *
  1230. * SYNOPSIS
  1231. *
  1232. * #include "glpnpp.h"
  1233. * int npp_make_fixed(NPP *npp, NPPCOL *q);
  1234. *
  1235. * DESCRIPTION
  1236. *
  1237. * The routine npp_make_fixed processes column q:
  1238. *
  1239. * l[q] <= x[q] <= u[q], (1)
  1240. *
  1241. * where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
  1242. * bounds.
  1243. *
  1244. * RETURNS
  1245. *
  1246. * 0 - column bounds have not been changed;
  1247. *
  1248. * 1 - column has been fixed.
  1249. *
  1250. * PROBLEM TRANSFORMATION
  1251. *
  1252. * If bounds of column (1) are very close to each other:
  1253. *
  1254. * u[q] - l[q] <= eps, (2)
  1255. *
  1256. * where eps is an absolute tolerance for column value, the column can
  1257. * be fixed:
  1258. *
  1259. * x[q] = s[q], (3)
  1260. *
  1261. * where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
  1262. * happens to be very close to its nearest integer:
  1263. *
  1264. * |s[q] - floor(s[q] + 0.5)| <= eps, (4)
  1265. *
  1266. * it is reasonable to use this nearest integer as the fixed value.
  1267. *
  1268. * RECOVERING BASIC SOLUTION
  1269. *
  1270. * In the dual system of the original (as well as transformed) problem
  1271. * column q corresponds to the following row:
  1272. *
  1273. * sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
  1274. * i
  1275. *
  1276. * Since multipliers pi[i] are known for all rows from solution to the
  1277. * transformed problem, formula (5) allows computing value of multiplier
  1278. * (reduced cost) for column q:
  1279. *
  1280. * lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
  1281. * i
  1282. *
  1283. * Status of column q in solution to the original problem is determined
  1284. * by its status and the sign of its multiplier lambda[q] in solution to
  1285. * the transformed problem as follows:
  1286. *
  1287. * +-----------------------+-----------+--------------------+
  1288. * | Status of column q | Sign of | Status of column q |
  1289. * | (transformed problem) | lambda[q] | (original problem) |
  1290. * +-----------------------+-----------+--------------------+
  1291. * | GLP_BS | + / - | GLP_BS |
  1292. * | GLP_NS | + | GLP_NL |
  1293. * | GLP_NS | - | GLP_NU |
  1294. * +-----------------------+-----------+--------------------+
  1295. *
  1296. * Value of column q in solution to the original problem is the same as
  1297. * in solution to the transformed problem.
  1298. *
  1299. * RECOVERING INTERIOR POINT SOLUTION
  1300. *
  1301. * Value of column q in solution to the original problem is the same as
  1302. * in solution to the transformed problem.
  1303. *
  1304. * RECOVERING MIP SOLUTION
  1305. *
  1306. * None needed. */
  1307. struct make_fixed
  1308. { /* column with almost identical bounds */
  1309. int q;
  1310. /* column reference number */
  1311. double c;
  1312. /* objective coefficient at x[q] */
  1313. NPPLFE *ptr;
  1314. /* list of non-zero coefficients a[i,q] */
  1315. };
  1316. static int rcv_make_fixed(NPP *npp, void *info);
  1317. int npp_make_fixed(NPP *npp, NPPCOL *q)
  1318. { /* process column with almost identical bounds */
  1319. struct make_fixed *info;
  1320. NPPAIJ *aij;
  1321. NPPLFE *lfe;
  1322. double s, eps, nint;
  1323. /* the column must be double-bounded */
  1324. xassert(q->lb != -DBL_MAX);
  1325. xassert(q->ub != +DBL_MAX);
  1326. xassert(q->lb < q->ub);
  1327. /* check column bounds */
  1328. eps = 1e-9 + 1e-12 * fabs(q->lb);
  1329. if (q->ub - q->lb > eps) return 0;
  1330. /* column bounds are very close to each other */
  1331. /* create transformation stack entry */
  1332. info = npp_push_tse(npp,
  1333. rcv_make_fixed, sizeof(struct make_fixed));
  1334. info->q = q->j;
  1335. info->c = q->coef;
  1336. info->ptr = NULL;
  1337. /* save column coefficients a[i,q] (needed for basic solution
  1338. only) */
  1339. if (npp->sol == GLP_SOL)
  1340. { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
  1341. { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
  1342. lfe->ref = aij->row->i;
  1343. lfe->val = aij->val;
  1344. lfe->next = info->ptr;
  1345. info->ptr = lfe;
  1346. }
  1347. }
  1348. /* compute column fixed value */
  1349. s = 0.5 * (q->ub + q->lb);
  1350. nint = floor(s + 0.5);
  1351. if (fabs(s - nint) <= eps) s = nint;
  1352. /* make column q fixed */
  1353. q->lb = q->ub = s;
  1354. return 1;
  1355. }
  1356. static int rcv_make_fixed(NPP *npp, void *_info)
  1357. { /* recover column with almost identical bounds */
  1358. struct make_fixed *info = _info;
  1359. NPPLFE *lfe;
  1360. double lambda;
  1361. if (npp->sol == GLP_SOL)
  1362. { if (npp->c_stat[info->q] == GLP_BS)
  1363. npp->c_stat[info->q] = GLP_BS;
  1364. else if (npp->c_stat[info->q] == GLP_NS)
  1365. { /* compute multiplier for column q with formula (6) */
  1366. lambda = info->c;
  1367. for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
  1368. lambda -= lfe->val * npp->r_pi[lfe->ref];
  1369. /* assign status to non-basic column */
  1370. if (lambda >= 0.0)
  1371. npp->c_stat[info->q] = GLP_NL;
  1372. else
  1373. npp->c_stat[info->q] = GLP_NU;
  1374. }
  1375. else
  1376. { npp_error();
  1377. return 1;
  1378. }
  1379. }
  1380. return 0;
  1381. }
  1382. /* eof */