You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1415 lines
49 KiB

  1. /* glpnpp04.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, 2011, 2013 Andrew Makhorin, Department for Applied
  7. * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
  8. * reserved. 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 "env.h"
  24. #include "glpnpp.h"
  25. /***********************************************************************
  26. * NAME
  27. *
  28. * npp_binarize_prob - binarize MIP problem
  29. *
  30. * SYNOPSIS
  31. *
  32. * #include "glpnpp.h"
  33. * int npp_binarize_prob(NPP *npp);
  34. *
  35. * DESCRIPTION
  36. *
  37. * The routine npp_binarize_prob replaces in the original MIP problem
  38. * every integer variable:
  39. *
  40. * l[q] <= x[q] <= u[q], (1)
  41. *
  42. * where l[q] < u[q], by an equivalent sum of binary variables.
  43. *
  44. * RETURNS
  45. *
  46. * The routine returns the number of integer variables for which the
  47. * transformation failed, because u[q] - l[q] > d_max.
  48. *
  49. * PROBLEM TRANSFORMATION
  50. *
  51. * If variable x[q] has non-zero lower bound, it is first processed
  52. * with the routine npp_lbnd_col. Thus, we can assume that:
  53. *
  54. * 0 <= x[q] <= u[q]. (2)
  55. *
  56. * If u[q] = 1, variable x[q] is already binary, so further processing
  57. * is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
  58. * smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
  59. * Then variable x[q] can be replaced by the following sum:
  60. *
  61. * n-1
  62. * x[q] = sum 2^k x[k], (3)
  63. * k=0
  64. *
  65. * where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
  66. * following additional inequality constraint must be also included in
  67. * the transformed problem:
  68. *
  69. * n-1
  70. * sum 2^k x[k] <= u[q]. (4)
  71. * k=0
  72. *
  73. * Note: Assuming that in the transformed problem x[q] becomes binary
  74. * variable x[0], this transformation causes new n-1 binary variables
  75. * to appear.
  76. *
  77. * Substituting x[q] from (3) to the objective row gives:
  78. *
  79. * z = sum c[j] x[j] + c[0] =
  80. * j
  81. *
  82. * = sum c[j] x[j] + c[q] x[q] + c[0] =
  83. * j!=q
  84. * n-1
  85. * = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
  86. * j!=q k=0
  87. * n-1
  88. * = sum c[j] x[j] + sum c[k] x[k] + c[0],
  89. * j!=q k=0
  90. *
  91. * where:
  92. *
  93. * c[k] = 2^k c[q], k = 0, ..., n-1. (5)
  94. *
  95. * And substituting x[q] from (3) to i-th constraint row i gives:
  96. *
  97. * L[i] <= sum a[i,j] x[j] <= U[i] ==>
  98. * j
  99. *
  100. * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
  101. * j!=q
  102. * n-1
  103. * L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i] ==>
  104. * j!=q k=0
  105. * n-1
  106. * L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
  107. * j!=q k=0
  108. *
  109. * where:
  110. *
  111. * a[i,k] = 2^k a[i,q], k = 0, ..., n-1. (6)
  112. *
  113. * RECOVERING SOLUTION
  114. *
  115. * Value of variable x[q] is computed with formula (3). */
  116. struct binarize
  117. { int q;
  118. /* column reference number for x[q] = x[0] */
  119. int j;
  120. /* column reference number for x[1]; x[2] has reference number
  121. j+1, x[3] - j+2, etc. */
  122. int n;
  123. /* total number of binary variables, n >= 2 */
  124. };
  125. static int rcv_binarize_prob(NPP *npp, void *info);
  126. int npp_binarize_prob(NPP *npp)
  127. { /* binarize MIP problem */
  128. struct binarize *info;
  129. NPPROW *row;
  130. NPPCOL *col, *bin;
  131. NPPAIJ *aij;
  132. int u, n, k, temp, nfails, nvars, nbins, nrows;
  133. /* new variables will be added to the end of the column list, so
  134. we go from the end to beginning of the column list */
  135. nfails = nvars = nbins = nrows = 0;
  136. for (col = npp->c_tail; col != NULL; col = col->prev)
  137. { /* skip continuous variable */
  138. if (!col->is_int) continue;
  139. /* skip fixed variable */
  140. if (col->lb == col->ub) continue;
  141. /* skip binary variable */
  142. if (col->lb == 0.0 && col->ub == 1.0) continue;
  143. /* check if the transformation is applicable */
  144. if (col->lb < -1e6 || col->ub > +1e6 ||
  145. col->ub - col->lb > 4095.0)
  146. { /* unfortunately, not */
  147. nfails++;
  148. continue;
  149. }
  150. /* process integer non-binary variable x[q] */
  151. nvars++;
  152. /* make x[q] non-negative, if its lower bound is non-zero */
  153. if (col->lb != 0.0)
  154. npp_lbnd_col(npp, col);
  155. /* now 0 <= x[q] <= u[q] */
  156. xassert(col->lb == 0.0);
  157. u = (int)col->ub;
  158. xassert(col->ub == (double)u);
  159. /* if x[q] is binary, further processing is not needed */
  160. if (u == 1) continue;
  161. /* determine smallest n such that u <= 2^n - 1 (thus, n is the
  162. number of binary variables needed) */
  163. n = 2, temp = 4;
  164. while (u >= temp)
  165. n++, temp += temp;
  166. nbins += n;
  167. /* create transformation stack entry */
  168. info = npp_push_tse(npp,
  169. rcv_binarize_prob, sizeof(struct binarize));
  170. info->q = col->j;
  171. info->j = 0; /* will be set below */
  172. info->n = n;
  173. /* if u < 2^n - 1, we need one additional row for (4) */
  174. if (u < temp - 1)
  175. { row = npp_add_row(npp), nrows++;
  176. row->lb = -DBL_MAX, row->ub = u;
  177. }
  178. else
  179. row = NULL;
  180. /* in the transformed problem variable x[q] becomes binary
  181. variable x[0], so its objective and constraint coefficients
  182. are not changed */
  183. col->ub = 1.0;
  184. /* include x[0] into constraint (4) */
  185. if (row != NULL)
  186. npp_add_aij(npp, row, col, 1.0);
  187. /* add other binary variables x[1], ..., x[n-1] */
  188. for (k = 1, temp = 2; k < n; k++, temp += temp)
  189. { /* add new binary variable x[k] */
  190. bin = npp_add_col(npp);
  191. bin->is_int = 1;
  192. bin->lb = 0.0, bin->ub = 1.0;
  193. bin->coef = (double)temp * col->coef;
  194. /* store column reference number for x[1] */
  195. if (info->j == 0)
  196. info->j = bin->j;
  197. else
  198. xassert(info->j + (k-1) == bin->j);
  199. /* duplicate constraint coefficients for x[k]; this also
  200. automatically includes x[k] into constraint (4) */
  201. for (aij = col->ptr; aij != NULL; aij = aij->c_next)
  202. npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
  203. }
  204. }
  205. if (nvars > 0)
  206. xprintf("%d integer variable(s) were replaced by %d binary one"
  207. "s\n", nvars, nbins);
  208. if (nrows > 0)
  209. xprintf("%d row(s) were added due to binarization\n", nrows);
  210. if (nfails > 0)
  211. xprintf("Binarization failed for %d integer variable(s)\n",
  212. nfails);
  213. return nfails;
  214. }
  215. static int rcv_binarize_prob(NPP *npp, void *_info)
  216. { /* recovery binarized variable */
  217. struct binarize *info = _info;
  218. int k, temp;
  219. double sum;
  220. /* compute value of x[q]; see formula (3) */
  221. sum = npp->c_value[info->q];
  222. for (k = 1, temp = 2; k < info->n; k++, temp += temp)
  223. sum += (double)temp * npp->c_value[info->j + (k-1)];
  224. npp->c_value[info->q] = sum;
  225. return 0;
  226. }
  227. /**********************************************************************/
  228. struct elem
  229. { /* linear form element a[j] x[j] */
  230. double aj;
  231. /* non-zero coefficient value */
  232. NPPCOL *xj;
  233. /* pointer to variable (column) */
  234. struct elem *next;
  235. /* pointer to another term */
  236. };
  237. static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
  238. { /* copy linear form */
  239. NPPAIJ *aij;
  240. struct elem *ptr, *e;
  241. ptr = NULL;
  242. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  243. { e = dmp_get_atom(npp->pool, sizeof(struct elem));
  244. e->aj = s * aij->val;
  245. e->xj = aij->col;
  246. e->next = ptr;
  247. ptr = e;
  248. }
  249. return ptr;
  250. }
  251. static void drop_form(NPP *npp, struct elem *ptr)
  252. { /* drop linear form */
  253. struct elem *e;
  254. while (ptr != NULL)
  255. { e = ptr;
  256. ptr = e->next;
  257. dmp_free_atom(npp->pool, e, sizeof(struct elem));
  258. }
  259. return;
  260. }
  261. /***********************************************************************
  262. * NAME
  263. *
  264. * npp_is_packing - test if constraint is packing inequality
  265. *
  266. * SYNOPSIS
  267. *
  268. * #include "glpnpp.h"
  269. * int npp_is_packing(NPP *npp, NPPROW *row);
  270. *
  271. * RETURNS
  272. *
  273. * If the specified row (constraint) is packing inequality (see below),
  274. * the routine npp_is_packing returns non-zero. Otherwise, it returns
  275. * zero.
  276. *
  277. * PACKING INEQUALITIES
  278. *
  279. * In canonical format the packing inequality is the following:
  280. *
  281. * sum x[j] <= 1, (1)
  282. * j in J
  283. *
  284. * where all variables x[j] are binary. This inequality expresses the
  285. * condition that in any integer feasible solution at most one variable
  286. * from set J can take non-zero (unity) value while other variables
  287. * must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
  288. * if J is empty or |J| = 1, the inequality (1) is redundant.
  289. *
  290. * In general case the packing inequality may include original variables
  291. * x[j] as well as their complements x~[j]:
  292. *
  293. * sum x[j] + sum x~[j] <= 1, (2)
  294. * j in Jp j in Jn
  295. *
  296. * where Jp and Jn are not intersected. Therefore, using substitution
  297. * x~[j] = 1 - x[j] gives the packing inequality in generalized format:
  298. *
  299. * sum x[j] - sum x[j] <= 1 - |Jn|. (3)
  300. * j in Jp j in Jn */
  301. int npp_is_packing(NPP *npp, NPPROW *row)
  302. { /* test if constraint is packing inequality */
  303. NPPCOL *col;
  304. NPPAIJ *aij;
  305. int b;
  306. xassert(npp == npp);
  307. if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
  308. return 0;
  309. b = 1;
  310. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  311. { col = aij->col;
  312. if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
  313. return 0;
  314. if (aij->val == +1.0)
  315. ;
  316. else if (aij->val == -1.0)
  317. b--;
  318. else
  319. return 0;
  320. }
  321. if (row->ub != (double)b) return 0;
  322. return 1;
  323. }
  324. /***********************************************************************
  325. * NAME
  326. *
  327. * npp_hidden_packing - identify hidden packing inequality
  328. *
  329. * SYNOPSIS
  330. *
  331. * #include "glpnpp.h"
  332. * int npp_hidden_packing(NPP *npp, NPPROW *row);
  333. *
  334. * DESCRIPTION
  335. *
  336. * The routine npp_hidden_packing processes specified inequality
  337. * constraint, which includes only binary variables, and the number of
  338. * the variables is not less than two. If the original inequality is
  339. * equivalent to a packing inequality, the routine replaces it by this
  340. * equivalent inequality. If the original constraint is double-sided
  341. * inequality, it is replaced by a pair of single-sided inequalities,
  342. * if necessary.
  343. *
  344. * RETURNS
  345. *
  346. * If the original inequality constraint was replaced by equivalent
  347. * packing inequality, the routine npp_hidden_packing returns non-zero.
  348. * Otherwise, it returns zero.
  349. *
  350. * PROBLEM TRANSFORMATION
  351. *
  352. * Consider an inequality constraint:
  353. *
  354. * sum a[j] x[j] <= b, (1)
  355. * j in J
  356. *
  357. * where all variables x[j] are binary, and |J| >= 2. (In case of '>='
  358. * inequality it can be transformed to '<=' format by multiplying both
  359. * its sides by -1.)
  360. *
  361. * Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
  362. * x[j] = 1 - x~[j] for all j in Jn, we have:
  363. *
  364. * sum a[j] x[j] <= b ==>
  365. * j in J
  366. *
  367. * sum a[j] x[j] + sum a[j] x[j] <= b ==>
  368. * j in Jp j in Jn
  369. *
  370. * sum a[j] x[j] + sum a[j] (1 - x~[j]) <= b ==>
  371. * j in Jp j in Jn
  372. *
  373. * sum a[j] x[j] - sum a[j] x~[j] <= b - sum a[j].
  374. * j in Jp j in Jn j in Jn
  375. *
  376. * Thus, meaning the transformation above, we can assume that in
  377. * inequality (1) all coefficients a[j] are positive. Moreover, we can
  378. * assume that a[j] <= b. In fact, let a[j] > b; then the following
  379. * three cases are possible:
  380. *
  381. * 1) b < 0. In this case inequality (1) is infeasible, so the problem
  382. * has no feasible solution (see the routine npp_analyze_row);
  383. *
  384. * 2) b = 0. In this case inequality (1) is a forcing inequality on its
  385. * upper bound (see the routine npp_forcing row), from which it
  386. * follows that all variables x[j] should be fixed at zero;
  387. *
  388. * 3) b > 0. In this case inequality (1) defines an implied zero upper
  389. * bound for variable x[j] (see the routine npp_implied_bounds), from
  390. * which it follows that x[j] should be fixed at zero.
  391. *
  392. * It is assumed that all three cases listed above have been recognized
  393. * by the routine npp_process_prob, which performs basic MIP processing
  394. * prior to a call the routine npp_hidden_packing. So, if one of these
  395. * cases occurs, we should just skip processing such constraint.
  396. *
  397. * Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
  398. * equivalent to packing inquality only if:
  399. *
  400. * a[j] + a[k] > b + eps (2)
  401. *
  402. * for all j, k in J, j != k, where eps is an absolute tolerance for
  403. * row (linear form) value. Checking the condition (2) for all j and k,
  404. * j != k, requires time O(|J|^2). However, this time can be reduced to
  405. * O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
  406. * to check the condition (2) only once.
  407. *
  408. * Once the original inequality (1) is replaced by equivalent packing
  409. * inequality, we need to perform back substitution x~[j] = 1 - x[j] for
  410. * all j in Jn (see above).
  411. *
  412. * RECOVERING SOLUTION
  413. *
  414. * None needed. */
  415. static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
  416. { /* process inequality constraint: sum a[j] x[j] <= b;
  417. 0 - specified row is NOT hidden packing inequality;
  418. 1 - specified row is packing inequality;
  419. 2 - specified row is hidden packing inequality. */
  420. struct elem *e, *ej, *ek;
  421. int neg;
  422. double b = *_b, eps;
  423. xassert(npp == npp);
  424. /* a[j] must be non-zero, x[j] must be binary, for all j in J */
  425. for (e = ptr; e != NULL; e = e->next)
  426. { xassert(e->aj != 0.0);
  427. xassert(e->xj->is_int);
  428. xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
  429. }
  430. /* check if the specified inequality constraint already has the
  431. form of packing inequality */
  432. neg = 0; /* neg is |Jn| */
  433. for (e = ptr; e != NULL; e = e->next)
  434. { if (e->aj == +1.0)
  435. ;
  436. else if (e->aj == -1.0)
  437. neg++;
  438. else
  439. break;
  440. }
  441. if (e == NULL)
  442. { /* all coefficients a[j] are +1 or -1; check rhs b */
  443. if (b == (double)(1 - neg))
  444. { /* it is packing inequality; no processing is needed */
  445. return 1;
  446. }
  447. }
  448. /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
  449. positive; the result is a~[j] = |a[j]| and new rhs b */
  450. for (e = ptr; e != NULL; e = e->next)
  451. if (e->aj < 0) b -= e->aj;
  452. /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
  453. /* if a[j] > b, skip processing--this case must not appear */
  454. for (e = ptr; e != NULL; e = e->next)
  455. if (fabs(e->aj) > b) return 0;
  456. /* now 0 < a[j] <= b for all j in J */
  457. /* find two minimal coefficients a[j] and a[k], j != k */
  458. ej = NULL;
  459. for (e = ptr; e != NULL; e = e->next)
  460. if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
  461. xassert(ej != NULL);
  462. ek = NULL;
  463. for (e = ptr; e != NULL; e = e->next)
  464. if (e != ej)
  465. if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
  466. xassert(ek != NULL);
  467. /* the specified constraint is equivalent to packing inequality
  468. iff a[j] + a[k] > b + eps */
  469. eps = 1e-3 + 1e-6 * fabs(b);
  470. if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
  471. /* perform back substitution x~[j] = 1 - x[j] and construct the
  472. final equivalent packing inequality in generalized format */
  473. b = 1.0;
  474. for (e = ptr; e != NULL; e = e->next)
  475. { if (e->aj > 0.0)
  476. e->aj = +1.0;
  477. else /* e->aj < 0.0 */
  478. e->aj = -1.0, b -= 1.0;
  479. }
  480. *_b = b;
  481. return 2;
  482. }
  483. int npp_hidden_packing(NPP *npp, NPPROW *row)
  484. { /* identify hidden packing inequality */
  485. NPPROW *copy;
  486. NPPAIJ *aij;
  487. struct elem *ptr, *e;
  488. int kase, ret, count = 0;
  489. double b;
  490. /* the row must be inequality constraint */
  491. xassert(row->lb < row->ub);
  492. for (kase = 0; kase <= 1; kase++)
  493. { if (kase == 0)
  494. { /* process row upper bound */
  495. if (row->ub == +DBL_MAX) continue;
  496. ptr = copy_form(npp, row, +1.0);
  497. b = + row->ub;
  498. }
  499. else
  500. { /* process row lower bound */
  501. if (row->lb == -DBL_MAX) continue;
  502. ptr = copy_form(npp, row, -1.0);
  503. b = - row->lb;
  504. }
  505. /* now the inequality has the form "sum a[j] x[j] <= b" */
  506. ret = hidden_packing(npp, ptr, &b);
  507. xassert(0 <= ret && ret <= 2);
  508. if (kase == 1 && ret == 1 || ret == 2)
  509. { /* the original inequality has been identified as hidden
  510. packing inequality */
  511. count++;
  512. #ifdef GLP_DEBUG
  513. xprintf("Original constraint:\n");
  514. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  515. xprintf(" %+g x%d", aij->val, aij->col->j);
  516. if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
  517. if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
  518. xprintf("\n");
  519. xprintf("Equivalent packing inequality:\n");
  520. for (e = ptr; e != NULL; e = e->next)
  521. xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
  522. xprintf(", <= %g\n", b);
  523. #endif
  524. if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
  525. { /* the original row is single-sided inequality; no copy
  526. is needed */
  527. copy = NULL;
  528. }
  529. else
  530. { /* the original row is double-sided inequality; we need
  531. to create its copy for other bound before replacing it
  532. with the equivalent inequality */
  533. copy = npp_add_row(npp);
  534. if (kase == 0)
  535. { /* the copy is for lower bound */
  536. copy->lb = row->lb, copy->ub = +DBL_MAX;
  537. }
  538. else
  539. { /* the copy is for upper bound */
  540. copy->lb = -DBL_MAX, copy->ub = row->ub;
  541. }
  542. /* copy original row coefficients */
  543. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  544. npp_add_aij(npp, copy, aij->col, aij->val);
  545. }
  546. /* replace the original inequality by equivalent one */
  547. npp_erase_row(npp, row);
  548. row->lb = -DBL_MAX, row->ub = b;
  549. for (e = ptr; e != NULL; e = e->next)
  550. npp_add_aij(npp, row, e->xj, e->aj);
  551. /* continue processing lower bound for the copy */
  552. if (copy != NULL) row = copy;
  553. }
  554. drop_form(npp, ptr);
  555. }
  556. return count;
  557. }
  558. /***********************************************************************
  559. * NAME
  560. *
  561. * npp_implied_packing - identify implied packing inequality
  562. *
  563. * SYNOPSIS
  564. *
  565. * #include "glpnpp.h"
  566. * int npp_implied_packing(NPP *npp, NPPROW *row, int which,
  567. * NPPCOL *var[], char set[]);
  568. *
  569. * DESCRIPTION
  570. *
  571. * The routine npp_implied_packing processes specified row (constraint)
  572. * of general format:
  573. *
  574. * L <= sum a[j] x[j] <= U. (1)
  575. * j
  576. *
  577. * If which = 0, only lower bound L, which must exist, is considered,
  578. * while upper bound U is ignored. Similarly, if which = 1, only upper
  579. * bound U, which must exist, is considered, while lower bound L is
  580. * ignored. Thus, if the specified row is a double-sided inequality or
  581. * equality constraint, this routine should be called twice for both
  582. * lower and upper bounds.
  583. *
  584. * The routine npp_implied_packing attempts to find a non-trivial (i.e.
  585. * having not less than two binary variables) packing inequality:
  586. *
  587. * sum x[j] - sum x[j] <= 1 - |Jn|, (2)
  588. * j in Jp j in Jn
  589. *
  590. * which is relaxation of the constraint (1) in the sense that any
  591. * solution satisfying to that constraint also satisfies to the packing
  592. * inequality (2). If such relaxation exists, the routine stores
  593. * pointers to descriptors of corresponding binary variables and their
  594. * flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
  595. * set[2], ..., set[len], where set[j] = 0 means that j in Jp and
  596. * set[j] = 1 means that j in Jn.
  597. *
  598. * RETURNS
  599. *
  600. * The routine npp_implied_packing returns len, which is the total
  601. * number of binary variables in the packing inequality found, len >= 2.
  602. * However, if the relaxation does not exist, the routine returns zero.
  603. *
  604. * ALGORITHM
  605. *
  606. * If which = 0, the constraint coefficients (1) are multiplied by -1
  607. * and b is assigned -L; if which = 1, the constraint coefficients (1)
  608. * are not changed and b is assigned +U. In both cases the specified
  609. * constraint gets the following format:
  610. *
  611. * sum a[j] x[j] <= b. (3)
  612. * j
  613. *
  614. * (Note that (3) is a relaxation of (1), because one of bounds L or U
  615. * is ignored.)
  616. *
  617. * Let J be set of binary variables, Kp be set of non-binary (integer
  618. * or continuous) variables with a[j] > 0, and Kn be set of non-binary
  619. * variables with a[j] < 0. Then the inequality (3) can be written as
  620. * follows:
  621. *
  622. * sum a[j] x[j] <= b - sum a[j] x[j] - sum a[j] x[j]. (4)
  623. * j in J j in Kp j in Kn
  624. *
  625. * To get rid of non-binary variables we can replace the inequality (4)
  626. * by the following relaxed inequality:
  627. *
  628. * sum a[j] x[j] <= b~, (5)
  629. * j in J
  630. *
  631. * where:
  632. *
  633. * b~ = sup(b - sum a[j] x[j] - sum a[j] x[j]) =
  634. * j in Kp j in Kn
  635. *
  636. * = b - inf sum a[j] x[j] - inf sum a[j] x[j] = (6)
  637. * j in Kp j in Kn
  638. *
  639. * = b - sum a[j] l[j] - sum a[j] u[j].
  640. * j in Kp j in Kn
  641. *
  642. * Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
  643. * (if j in Kn) of some non-binary variable x[j] does not exist, then
  644. * formally b = +oo, in which case further analysis is not performed.
  645. *
  646. * Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
  647. * the inequality coefficients in (5) positive, we replace all x[j] in
  648. * Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
  649. * j in Bn, that gives:
  650. *
  651. * sum a[j] x[j] - sum a[j] x~[j] <= b~ - sum a[j]. (7)
  652. * j in Bp j in Bn j in Bn
  653. *
  654. * This inequality is a relaxation of the original constraint (1), and
  655. * it is a binary knapsack inequality. Writing it in the standard format
  656. * we have:
  657. *
  658. * sum alfa[j] z[j] <= beta, (8)
  659. * j in J
  660. *
  661. * where:
  662. * ( + a[j], if j in Bp,
  663. * alfa[j] = < (9)
  664. * ( - a[j], if j in Bn,
  665. *
  666. * ( x[j], if j in Bp,
  667. * z[j] = < (10)
  668. * ( 1 - x[j], if j in Bn,
  669. *
  670. * beta = b~ - sum a[j]. (11)
  671. * j in Bn
  672. *
  673. * In the inequality (8) all coefficients are positive, therefore, the
  674. * packing relaxation to be found for this inequality is the following:
  675. *
  676. * sum z[j] <= 1. (12)
  677. * j in P
  678. *
  679. * It is obvious that set P within J, which we would like to find, must
  680. * satisfy to the following condition:
  681. *
  682. * alfa[j] + alfa[k] > beta + eps for all j, k in P, j != k, (13)
  683. *
  684. * where eps is an absolute tolerance for value of the linear form.
  685. * Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
  686. * Moreover, if in the equality (8) there exist coefficients alfa[k],
  687. * for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
  688. * satisfies to the condition (13) for all j in P, *one* corresponding
  689. * variable z[k] (having, for example, maximal coefficient alfa[k]) can
  690. * be included in set P, that allows increasing the number of binary
  691. * variables in (12) by one.
  692. *
  693. * Once the set P has been built, for the inequality (12) we need to
  694. * perform back substitution according to (10) in order to express it
  695. * through the original binary variables. As the result of such back
  696. * substitution the relaxed packing inequality get its final format (2),
  697. * where Jp = J intersect Bp, and Jn = J intersect Bn. */
  698. int npp_implied_packing(NPP *npp, NPPROW *row, int which,
  699. NPPCOL *var[], char set[])
  700. { struct elem *ptr, *e, *i, *k;
  701. int len = 0;
  702. double b, eps;
  703. /* build inequality (3) */
  704. if (which == 0)
  705. { ptr = copy_form(npp, row, -1.0);
  706. xassert(row->lb != -DBL_MAX);
  707. b = - row->lb;
  708. }
  709. else if (which == 1)
  710. { ptr = copy_form(npp, row, +1.0);
  711. xassert(row->ub != +DBL_MAX);
  712. b = + row->ub;
  713. }
  714. /* remove non-binary variables to build relaxed inequality (5);
  715. compute its right-hand side b~ with formula (6) */
  716. for (e = ptr; e != NULL; e = e->next)
  717. { if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
  718. { /* x[j] is non-binary variable */
  719. if (e->aj > 0.0)
  720. { if (e->xj->lb == -DBL_MAX) goto done;
  721. b -= e->aj * e->xj->lb;
  722. }
  723. else /* e->aj < 0.0 */
  724. { if (e->xj->ub == +DBL_MAX) goto done;
  725. b -= e->aj * e->xj->ub;
  726. }
  727. /* a[j] = 0 means that variable x[j] is removed */
  728. e->aj = 0.0;
  729. }
  730. }
  731. /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
  732. compute its right-hand side beta with formula (11) */
  733. for (e = ptr; e != NULL; e = e->next)
  734. if (e->aj < 0.0) b -= e->aj;
  735. /* if beta is close to zero, the knapsack inequality is either
  736. infeasible or forcing inequality; this must never happen, so
  737. we skip further analysis */
  738. if (b < 1e-3) goto done;
  739. /* build set P as well as sets Jp and Jn, and determine x[k] as
  740. explained above in comments to the routine */
  741. eps = 1e-3 + 1e-6 * b;
  742. i = k = NULL;
  743. for (e = ptr; e != NULL; e = e->next)
  744. { /* note that alfa[j] = |a[j]| */
  745. if (fabs(e->aj) > 0.5 * (b + eps))
  746. { /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
  747. set Jp or Jn */
  748. var[++len] = e->xj;
  749. set[len] = (char)(e->aj > 0.0 ? 0 : 1);
  750. /* alfa[i] = min alfa[j] over all j included in set P */
  751. if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
  752. }
  753. else if (fabs(e->aj) >= 1e-3)
  754. { /* alfa[k] = max alfa[j] over all j not included in set P;
  755. we skip coefficient a[j] if it is close to zero to avoid
  756. numerically unreliable results */
  757. if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
  758. }
  759. }
  760. /* if alfa[k] satisfies to condition (13) for all j in P, include
  761. x[k] in P */
  762. if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
  763. { var[++len] = k->xj;
  764. set[len] = (char)(k->aj > 0.0 ? 0 : 1);
  765. }
  766. /* trivial packing inequality being redundant must never appear,
  767. so we just ignore it */
  768. if (len < 2) len = 0;
  769. done: drop_form(npp, ptr);
  770. return len;
  771. }
  772. /***********************************************************************
  773. * NAME
  774. *
  775. * npp_is_covering - test if constraint is covering inequality
  776. *
  777. * SYNOPSIS
  778. *
  779. * #include "glpnpp.h"
  780. * int npp_is_covering(NPP *npp, NPPROW *row);
  781. *
  782. * RETURNS
  783. *
  784. * If the specified row (constraint) is covering inequality (see below),
  785. * the routine npp_is_covering returns non-zero. Otherwise, it returns
  786. * zero.
  787. *
  788. * COVERING INEQUALITIES
  789. *
  790. * In canonical format the covering inequality is the following:
  791. *
  792. * sum x[j] >= 1, (1)
  793. * j in J
  794. *
  795. * where all variables x[j] are binary. This inequality expresses the
  796. * condition that in any integer feasible solution variables in set J
  797. * cannot be all equal to zero at the same time, i.e. at least one
  798. * variable must take non-zero (unity) value. W.l.o.g. it is assumed
  799. * that |J| >= 2, because if J is empty, the inequality (1) is
  800. * infeasible, and if |J| = 1, the inequality (1) is a forcing row.
  801. *
  802. * In general case the covering inequality may include original
  803. * variables x[j] as well as their complements x~[j]:
  804. *
  805. * sum x[j] + sum x~[j] >= 1, (2)
  806. * j in Jp j in Jn
  807. *
  808. * where Jp and Jn are not intersected. Therefore, using substitution
  809. * x~[j] = 1 - x[j] gives the packing inequality in generalized format:
  810. *
  811. * sum x[j] - sum x[j] >= 1 - |Jn|. (3)
  812. * j in Jp j in Jn
  813. *
  814. * (May note that the inequality (3) cuts off infeasible solutions,
  815. * where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
  816. *
  817. * NOTE: If |J| = 2, the inequality (3) is equivalent to packing
  818. * inequality (see the routine npp_is_packing). */
  819. int npp_is_covering(NPP *npp, NPPROW *row)
  820. { /* test if constraint is covering inequality */
  821. NPPCOL *col;
  822. NPPAIJ *aij;
  823. int b;
  824. xassert(npp == npp);
  825. if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
  826. return 0;
  827. b = 1;
  828. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  829. { col = aij->col;
  830. if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
  831. return 0;
  832. if (aij->val == +1.0)
  833. ;
  834. else if (aij->val == -1.0)
  835. b--;
  836. else
  837. return 0;
  838. }
  839. if (row->lb != (double)b) return 0;
  840. return 1;
  841. }
  842. /***********************************************************************
  843. * NAME
  844. *
  845. * npp_hidden_covering - identify hidden covering inequality
  846. *
  847. * SYNOPSIS
  848. *
  849. * #include "glpnpp.h"
  850. * int npp_hidden_covering(NPP *npp, NPPROW *row);
  851. *
  852. * DESCRIPTION
  853. *
  854. * The routine npp_hidden_covering processes specified inequality
  855. * constraint, which includes only binary variables, and the number of
  856. * the variables is not less than three. If the original inequality is
  857. * equivalent to a covering inequality (see below), the routine
  858. * replaces it by the equivalent inequality. If the original constraint
  859. * is double-sided inequality, it is replaced by a pair of single-sided
  860. * inequalities, if necessary.
  861. *
  862. * RETURNS
  863. *
  864. * If the original inequality constraint was replaced by equivalent
  865. * covering inequality, the routine npp_hidden_covering returns
  866. * non-zero. Otherwise, it returns zero.
  867. *
  868. * PROBLEM TRANSFORMATION
  869. *
  870. * Consider an inequality constraint:
  871. *
  872. * sum a[j] x[j] >= b, (1)
  873. * j in J
  874. *
  875. * where all variables x[j] are binary, and |J| >= 3. (In case of '<='
  876. * inequality it can be transformed to '>=' format by multiplying both
  877. * its sides by -1.)
  878. *
  879. * Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
  880. * x[j] = 1 - x~[j] for all j in Jn, we have:
  881. *
  882. * sum a[j] x[j] >= b ==>
  883. * j in J
  884. *
  885. * sum a[j] x[j] + sum a[j] x[j] >= b ==>
  886. * j in Jp j in Jn
  887. *
  888. * sum a[j] x[j] + sum a[j] (1 - x~[j]) >= b ==>
  889. * j in Jp j in Jn
  890. *
  891. * sum m a[j] x[j] - sum a[j] x~[j] >= b - sum a[j].
  892. * j in Jp j in Jn j in Jn
  893. *
  894. * Thus, meaning the transformation above, we can assume that in
  895. * inequality (1) all coefficients a[j] are positive. Moreover, we can
  896. * assume that b > 0, because otherwise the inequality (1) would be
  897. * redundant (see the routine npp_analyze_row). It is then obvious that
  898. * constraint (1) is equivalent to covering inequality only if:
  899. *
  900. * a[j] >= b, (2)
  901. *
  902. * for all j in J.
  903. *
  904. * Once the original inequality (1) is replaced by equivalent covering
  905. * inequality, we need to perform back substitution x~[j] = 1 - x[j] for
  906. * all j in Jn (see above).
  907. *
  908. * RECOVERING SOLUTION
  909. *
  910. * None needed. */
  911. static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
  912. { /* process inequality constraint: sum a[j] x[j] >= b;
  913. 0 - specified row is NOT hidden covering inequality;
  914. 1 - specified row is covering inequality;
  915. 2 - specified row is hidden covering inequality. */
  916. struct elem *e;
  917. int neg;
  918. double b = *_b, eps;
  919. xassert(npp == npp);
  920. /* a[j] must be non-zero, x[j] must be binary, for all j in J */
  921. for (e = ptr; e != NULL; e = e->next)
  922. { xassert(e->aj != 0.0);
  923. xassert(e->xj->is_int);
  924. xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
  925. }
  926. /* check if the specified inequality constraint already has the
  927. form of covering inequality */
  928. neg = 0; /* neg is |Jn| */
  929. for (e = ptr; e != NULL; e = e->next)
  930. { if (e->aj == +1.0)
  931. ;
  932. else if (e->aj == -1.0)
  933. neg++;
  934. else
  935. break;
  936. }
  937. if (e == NULL)
  938. { /* all coefficients a[j] are +1 or -1; check rhs b */
  939. if (b == (double)(1 - neg))
  940. { /* it is covering inequality; no processing is needed */
  941. return 1;
  942. }
  943. }
  944. /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
  945. positive; the result is a~[j] = |a[j]| and new rhs b */
  946. for (e = ptr; e != NULL; e = e->next)
  947. if (e->aj < 0) b -= e->aj;
  948. /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
  949. /* if b <= 0, skip processing--this case must not appear */
  950. if (b < 1e-3) return 0;
  951. /* now a[j] > 0 for all j in J, and b > 0 */
  952. /* the specified constraint is equivalent to covering inequality
  953. iff a[j] >= b for all j in J */
  954. eps = 1e-9 + 1e-12 * fabs(b);
  955. for (e = ptr; e != NULL; e = e->next)
  956. if (fabs(e->aj) < b - eps) return 0;
  957. /* perform back substitution x~[j] = 1 - x[j] and construct the
  958. final equivalent covering inequality in generalized format */
  959. b = 1.0;
  960. for (e = ptr; e != NULL; e = e->next)
  961. { if (e->aj > 0.0)
  962. e->aj = +1.0;
  963. else /* e->aj < 0.0 */
  964. e->aj = -1.0, b -= 1.0;
  965. }
  966. *_b = b;
  967. return 2;
  968. }
  969. int npp_hidden_covering(NPP *npp, NPPROW *row)
  970. { /* identify hidden covering inequality */
  971. NPPROW *copy;
  972. NPPAIJ *aij;
  973. struct elem *ptr, *e;
  974. int kase, ret, count = 0;
  975. double b;
  976. /* the row must be inequality constraint */
  977. xassert(row->lb < row->ub);
  978. for (kase = 0; kase <= 1; kase++)
  979. { if (kase == 0)
  980. { /* process row lower bound */
  981. if (row->lb == -DBL_MAX) continue;
  982. ptr = copy_form(npp, row, +1.0);
  983. b = + row->lb;
  984. }
  985. else
  986. { /* process row upper bound */
  987. if (row->ub == +DBL_MAX) continue;
  988. ptr = copy_form(npp, row, -1.0);
  989. b = - row->ub;
  990. }
  991. /* now the inequality has the form "sum a[j] x[j] >= b" */
  992. ret = hidden_covering(npp, ptr, &b);
  993. xassert(0 <= ret && ret <= 2);
  994. if (kase == 1 && ret == 1 || ret == 2)
  995. { /* the original inequality has been identified as hidden
  996. covering inequality */
  997. count++;
  998. #ifdef GLP_DEBUG
  999. xprintf("Original constraint:\n");
  1000. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1001. xprintf(" %+g x%d", aij->val, aij->col->j);
  1002. if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
  1003. if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
  1004. xprintf("\n");
  1005. xprintf("Equivalent covering inequality:\n");
  1006. for (e = ptr; e != NULL; e = e->next)
  1007. xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
  1008. xprintf(", >= %g\n", b);
  1009. #endif
  1010. if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
  1011. { /* the original row is single-sided inequality; no copy
  1012. is needed */
  1013. copy = NULL;
  1014. }
  1015. else
  1016. { /* the original row is double-sided inequality; we need
  1017. to create its copy for other bound before replacing it
  1018. with the equivalent inequality */
  1019. copy = npp_add_row(npp);
  1020. if (kase == 0)
  1021. { /* the copy is for upper bound */
  1022. copy->lb = -DBL_MAX, copy->ub = row->ub;
  1023. }
  1024. else
  1025. { /* the copy is for lower bound */
  1026. copy->lb = row->lb, copy->ub = +DBL_MAX;
  1027. }
  1028. /* copy original row coefficients */
  1029. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1030. npp_add_aij(npp, copy, aij->col, aij->val);
  1031. }
  1032. /* replace the original inequality by equivalent one */
  1033. npp_erase_row(npp, row);
  1034. row->lb = b, row->ub = +DBL_MAX;
  1035. for (e = ptr; e != NULL; e = e->next)
  1036. npp_add_aij(npp, row, e->xj, e->aj);
  1037. /* continue processing upper bound for the copy */
  1038. if (copy != NULL) row = copy;
  1039. }
  1040. drop_form(npp, ptr);
  1041. }
  1042. return count;
  1043. }
  1044. /***********************************************************************
  1045. * NAME
  1046. *
  1047. * npp_is_partitioning - test if constraint is partitioning equality
  1048. *
  1049. * SYNOPSIS
  1050. *
  1051. * #include "glpnpp.h"
  1052. * int npp_is_partitioning(NPP *npp, NPPROW *row);
  1053. *
  1054. * RETURNS
  1055. *
  1056. * If the specified row (constraint) is partitioning equality (see
  1057. * below), the routine npp_is_partitioning returns non-zero. Otherwise,
  1058. * it returns zero.
  1059. *
  1060. * PARTITIONING EQUALITIES
  1061. *
  1062. * In canonical format the partitioning equality is the following:
  1063. *
  1064. * sum x[j] = 1, (1)
  1065. * j in J
  1066. *
  1067. * where all variables x[j] are binary. This equality expresses the
  1068. * condition that in any integer feasible solution exactly one variable
  1069. * in set J must take non-zero (unity) value while other variables must
  1070. * be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
  1071. * J is empty, the inequality (1) is infeasible, and if |J| = 1, the
  1072. * inequality (1) is a fixing row.
  1073. *
  1074. * In general case the partitioning equality may include original
  1075. * variables x[j] as well as their complements x~[j]:
  1076. *
  1077. * sum x[j] + sum x~[j] = 1, (2)
  1078. * j in Jp j in Jn
  1079. *
  1080. * where Jp and Jn are not intersected. Therefore, using substitution
  1081. * x~[j] = 1 - x[j] leads to the partitioning equality in generalized
  1082. * format:
  1083. *
  1084. * sum x[j] - sum x[j] = 1 - |Jn|. (3)
  1085. * j in Jp j in Jn */
  1086. int npp_is_partitioning(NPP *npp, NPPROW *row)
  1087. { /* test if constraint is partitioning equality */
  1088. NPPCOL *col;
  1089. NPPAIJ *aij;
  1090. int b;
  1091. xassert(npp == npp);
  1092. if (row->lb != row->ub) return 0;
  1093. b = 1;
  1094. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1095. { col = aij->col;
  1096. if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
  1097. return 0;
  1098. if (aij->val == +1.0)
  1099. ;
  1100. else if (aij->val == -1.0)
  1101. b--;
  1102. else
  1103. return 0;
  1104. }
  1105. if (row->lb != (double)b) return 0;
  1106. return 1;
  1107. }
  1108. /***********************************************************************
  1109. * NAME
  1110. *
  1111. * npp_reduce_ineq_coef - reduce inequality constraint coefficients
  1112. *
  1113. * SYNOPSIS
  1114. *
  1115. * #include "glpnpp.h"
  1116. * int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
  1117. *
  1118. * DESCRIPTION
  1119. *
  1120. * The routine npp_reduce_ineq_coef processes specified inequality
  1121. * constraint attempting to replace it by an equivalent constraint,
  1122. * where magnitude of coefficients at binary variables is smaller than
  1123. * in the original constraint. If the inequality is double-sided, it is
  1124. * replaced by a pair of single-sided inequalities, if necessary.
  1125. *
  1126. * RETURNS
  1127. *
  1128. * The routine npp_reduce_ineq_coef returns the number of coefficients
  1129. * reduced.
  1130. *
  1131. * BACKGROUND
  1132. *
  1133. * Consider an inequality constraint:
  1134. *
  1135. * sum a[j] x[j] >= b. (1)
  1136. * j in J
  1137. *
  1138. * (In case of '<=' inequality it can be transformed to '>=' format by
  1139. * multiplying both its sides by -1.) Let x[k] be a binary variable;
  1140. * other variables can be integer as well as continuous. We can write
  1141. * constraint (1) as follows:
  1142. *
  1143. * a[k] x[k] + t[k] >= b, (2)
  1144. *
  1145. * where:
  1146. *
  1147. * t[k] = sum a[j] x[j]. (3)
  1148. * j in J\{k}
  1149. *
  1150. * Since x[k] is binary, constraint (2) is equivalent to disjunction of
  1151. * the following two constraints:
  1152. *
  1153. * x[k] = 0, t[k] >= b (4)
  1154. *
  1155. * OR
  1156. *
  1157. * x[k] = 1, t[k] >= b - a[k]. (5)
  1158. *
  1159. * Let also that for the partial sum t[k] be known some its implied
  1160. * lower bound inf t[k].
  1161. *
  1162. * Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
  1163. * (4) and (5) and therefore constraint (2) are redundant.
  1164. * If inf t[k] > b - a[k], only constraint (5) is redundant, in which
  1165. * case it can be replaced with the following redundant and therefore
  1166. * equivalent constraint:
  1167. *
  1168. * t[k] >= b - a'[k] = inf t[k], (6)
  1169. *
  1170. * where:
  1171. *
  1172. * a'[k] = b - inf t[k]. (7)
  1173. *
  1174. * Thus, the original constraint (2) is equivalent to the following
  1175. * constraint with coefficient at variable x[k] changed:
  1176. *
  1177. * a'[k] x[k] + t[k] >= b. (8)
  1178. *
  1179. * From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
  1180. * at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
  1181. * a'[k] < a[k], i.e. the coefficient reduces in magnitude.
  1182. *
  1183. * Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
  1184. * constraints (4) and (5) and therefore constraint (2) are redundant.
  1185. * If inf t[k] > b, only constraint (4) is redundant, in which case it
  1186. * can be replaced with the following redundant and therefore equivalent
  1187. * constraint:
  1188. *
  1189. * t[k] >= b' = inf t[k]. (9)
  1190. *
  1191. * Rewriting constraint (5) as follows:
  1192. *
  1193. * t[k] >= b - a[k] = b' - a'[k], (10)
  1194. *
  1195. * where:
  1196. *
  1197. * a'[k] = a[k] + b' - b = a[k] + inf t[k] - b, (11)
  1198. *
  1199. * we can see that disjunction of constraint (9) and (10) is equivalent
  1200. * to disjunction of constraint (4) and (5), from which it follows that
  1201. * the original constraint (2) is equivalent to the following constraint
  1202. * with both coefficient at variable x[k] and right-hand side changed:
  1203. *
  1204. * a'[k] x[k] + t[k] >= b'. (12)
  1205. *
  1206. * From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
  1207. * coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
  1208. * that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
  1209. *
  1210. * PROBLEM TRANSFORMATION
  1211. *
  1212. * In the routine npp_reduce_ineq_coef the following implied lower
  1213. * bound of the partial sum (3) is used:
  1214. *
  1215. * inf t[k] = sum a[j] l[j] + sum a[j] u[j], (13)
  1216. * j in Jp\{k} k in Jn\{k}
  1217. *
  1218. * where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
  1219. * lower and upper bounds, resp., of variable x[j].
  1220. *
  1221. * In order to compute inf t[k] more efficiently, the following formula,
  1222. * which is equivalent to (13), is actually used:
  1223. *
  1224. * ( h - a[k] l[k] = h, if a[k] > 0,
  1225. * inf t[k] = < (14)
  1226. * ( h - a[k] u[k] = h - a[k], if a[k] < 0,
  1227. *
  1228. * where:
  1229. *
  1230. * h = sum a[j] l[j] + sum a[j] u[j] (15)
  1231. * j in Jp j in Jn
  1232. *
  1233. * is the implied lower bound of row (1).
  1234. *
  1235. * Reduction of positive coefficient (a[k] > 0) does not change value
  1236. * of h, since l[k] = 0. In case of reduction of negative coefficient
  1237. * (a[k] < 0) from (11) it follows that:
  1238. *
  1239. * delta a[k] = a'[k] - a[k] = inf t[k] - b (> 0), (16)
  1240. *
  1241. * so new value of h (accounting that u[k] = 1) can be computed as
  1242. * follows:
  1243. *
  1244. * h := h + delta a[k] = h + (inf t[k] - b). (17)
  1245. *
  1246. * RECOVERING SOLUTION
  1247. *
  1248. * None needed. */
  1249. static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
  1250. { /* process inequality constraint: sum a[j] x[j] >= b */
  1251. /* returns: the number of coefficients reduced */
  1252. struct elem *e;
  1253. int count = 0;
  1254. double h, inf_t, new_a, b = *_b;
  1255. xassert(npp == npp);
  1256. /* compute h; see (15) */
  1257. h = 0.0;
  1258. for (e = ptr; e != NULL; e = e->next)
  1259. { if (e->aj > 0.0)
  1260. { if (e->xj->lb == -DBL_MAX) goto done;
  1261. h += e->aj * e->xj->lb;
  1262. }
  1263. else /* e->aj < 0.0 */
  1264. { if (e->xj->ub == +DBL_MAX) goto done;
  1265. h += e->aj * e->xj->ub;
  1266. }
  1267. }
  1268. /* perform reduction of coefficients at binary variables */
  1269. for (e = ptr; e != NULL; e = e->next)
  1270. { /* skip non-binary variable */
  1271. if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
  1272. continue;
  1273. if (e->aj > 0.0)
  1274. { /* compute inf t[k]; see (14) */
  1275. inf_t = h;
  1276. if (b - e->aj < inf_t && inf_t < b)
  1277. { /* compute reduced coefficient a'[k]; see (7) */
  1278. new_a = b - inf_t;
  1279. if (new_a >= +1e-3 &&
  1280. e->aj - new_a >= 0.01 * (1.0 + e->aj))
  1281. { /* accept a'[k] */
  1282. #ifdef GLP_DEBUG
  1283. xprintf("+");
  1284. #endif
  1285. e->aj = new_a;
  1286. count++;
  1287. }
  1288. }
  1289. }
  1290. else /* e->aj < 0.0 */
  1291. { /* compute inf t[k]; see (14) */
  1292. inf_t = h - e->aj;
  1293. if (b < inf_t && inf_t < b - e->aj)
  1294. { /* compute reduced coefficient a'[k]; see (11) */
  1295. new_a = e->aj + (inf_t - b);
  1296. if (new_a <= -1e-3 &&
  1297. new_a - e->aj >= 0.01 * (1.0 - e->aj))
  1298. { /* accept a'[k] */
  1299. #ifdef GLP_DEBUG
  1300. xprintf("-");
  1301. #endif
  1302. e->aj = new_a;
  1303. /* update h; see (17) */
  1304. h += (inf_t - b);
  1305. /* compute b'; see (9) */
  1306. b = inf_t;
  1307. count++;
  1308. }
  1309. }
  1310. }
  1311. }
  1312. *_b = b;
  1313. done: return count;
  1314. }
  1315. int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
  1316. { /* reduce inequality constraint coefficients */
  1317. NPPROW *copy;
  1318. NPPAIJ *aij;
  1319. struct elem *ptr, *e;
  1320. int kase, count[2];
  1321. double b;
  1322. /* the row must be inequality constraint */
  1323. xassert(row->lb < row->ub);
  1324. count[0] = count[1] = 0;
  1325. for (kase = 0; kase <= 1; kase++)
  1326. { if (kase == 0)
  1327. { /* process row lower bound */
  1328. if (row->lb == -DBL_MAX) continue;
  1329. #ifdef GLP_DEBUG
  1330. xprintf("L");
  1331. #endif
  1332. ptr = copy_form(npp, row, +1.0);
  1333. b = + row->lb;
  1334. }
  1335. else
  1336. { /* process row upper bound */
  1337. if (row->ub == +DBL_MAX) continue;
  1338. #ifdef GLP_DEBUG
  1339. xprintf("U");
  1340. #endif
  1341. ptr = copy_form(npp, row, -1.0);
  1342. b = - row->ub;
  1343. }
  1344. /* now the inequality has the form "sum a[j] x[j] >= b" */
  1345. count[kase] = reduce_ineq_coef(npp, ptr, &b);
  1346. if (count[kase] > 0)
  1347. { /* the original inequality has been replaced by equivalent
  1348. one with coefficients reduced */
  1349. if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
  1350. { /* the original row is single-sided inequality; no copy
  1351. is needed */
  1352. copy = NULL;
  1353. }
  1354. else
  1355. { /* the original row is double-sided inequality; we need
  1356. to create its copy for other bound before replacing it
  1357. with the equivalent inequality */
  1358. #ifdef GLP_DEBUG
  1359. xprintf("*");
  1360. #endif
  1361. copy = npp_add_row(npp);
  1362. if (kase == 0)
  1363. { /* the copy is for upper bound */
  1364. copy->lb = -DBL_MAX, copy->ub = row->ub;
  1365. }
  1366. else
  1367. { /* the copy is for lower bound */
  1368. copy->lb = row->lb, copy->ub = +DBL_MAX;
  1369. }
  1370. /* copy original row coefficients */
  1371. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1372. npp_add_aij(npp, copy, aij->col, aij->val);
  1373. }
  1374. /* replace the original inequality by equivalent one */
  1375. npp_erase_row(npp, row);
  1376. row->lb = b, row->ub = +DBL_MAX;
  1377. for (e = ptr; e != NULL; e = e->next)
  1378. npp_add_aij(npp, row, e->xj, e->aj);
  1379. /* continue processing upper bound for the copy */
  1380. if (copy != NULL) row = copy;
  1381. }
  1382. drop_form(npp, ptr);
  1383. }
  1384. return count[0] + count[1];
  1385. }
  1386. /* eof */