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.

810 lines
26 KiB

  1. /* glpnpp05.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_clean_prob - perform initial LP/MIP processing
  29. *
  30. * SYNOPSIS
  31. *
  32. * #include "glpnpp.h"
  33. * void npp_clean_prob(NPP *npp);
  34. *
  35. * DESCRIPTION
  36. *
  37. * The routine npp_clean_prob performs initial LP/MIP processing that
  38. * currently includes:
  39. *
  40. * 1) removing free rows;
  41. *
  42. * 2) replacing double-sided constraint rows with almost identical
  43. * bounds, by equality constraint rows;
  44. *
  45. * 3) removing fixed columns;
  46. *
  47. * 4) replacing double-bounded columns with almost identical bounds by
  48. * fixed columns and removing those columns;
  49. *
  50. * 5) initial processing constraint coefficients (not implemented);
  51. *
  52. * 6) initial processing objective coefficients (not implemented). */
  53. void npp_clean_prob(NPP *npp)
  54. { /* perform initial LP/MIP processing */
  55. NPPROW *row, *next_row;
  56. NPPCOL *col, *next_col;
  57. int ret;
  58. xassert(npp == npp);
  59. /* process rows which originally are free */
  60. for (row = npp->r_head; row != NULL; row = next_row)
  61. { next_row = row->next;
  62. if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
  63. { /* process free row */
  64. #ifdef GLP_DEBUG
  65. xprintf("1");
  66. #endif
  67. npp_free_row(npp, row);
  68. /* row was deleted */
  69. }
  70. }
  71. /* process rows which originally are double-sided inequalities */
  72. for (row = npp->r_head; row != NULL; row = next_row)
  73. { next_row = row->next;
  74. if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
  75. row->lb < row->ub)
  76. { ret = npp_make_equality(npp, row);
  77. if (ret == 0)
  78. ;
  79. else if (ret == 1)
  80. { /* row was replaced by equality constraint */
  81. #ifdef GLP_DEBUG
  82. xprintf("2");
  83. #endif
  84. }
  85. else
  86. xassert(ret != ret);
  87. }
  88. }
  89. /* process columns which are originally fixed */
  90. for (col = npp->c_head; col != NULL; col = next_col)
  91. { next_col = col->next;
  92. if (col->lb == col->ub)
  93. { /* process fixed column */
  94. #ifdef GLP_DEBUG
  95. xprintf("3");
  96. #endif
  97. npp_fixed_col(npp, col);
  98. /* column was deleted */
  99. }
  100. }
  101. /* process columns which are originally double-bounded */
  102. for (col = npp->c_head; col != NULL; col = next_col)
  103. { next_col = col->next;
  104. if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
  105. col->lb < col->ub)
  106. { ret = npp_make_fixed(npp, col);
  107. if (ret == 0)
  108. ;
  109. else if (ret == 1)
  110. { /* column was replaced by fixed column; process it */
  111. #ifdef GLP_DEBUG
  112. xprintf("4");
  113. #endif
  114. npp_fixed_col(npp, col);
  115. /* column was deleted */
  116. }
  117. }
  118. }
  119. return;
  120. }
  121. /***********************************************************************
  122. * NAME
  123. *
  124. * npp_process_row - perform basic row processing
  125. *
  126. * SYNOPSIS
  127. *
  128. * #include "glpnpp.h"
  129. * int npp_process_row(NPP *npp, NPPROW *row, int hard);
  130. *
  131. * DESCRIPTION
  132. *
  133. * The routine npp_process_row performs basic row processing that
  134. * currently includes:
  135. *
  136. * 1) removing empty row;
  137. *
  138. * 2) removing equality constraint row singleton and corresponding
  139. * column;
  140. *
  141. * 3) removing inequality constraint row singleton and corresponding
  142. * column if it was fixed;
  143. *
  144. * 4) performing general row analysis;
  145. *
  146. * 5) removing redundant row bounds;
  147. *
  148. * 6) removing forcing row and corresponding columns;
  149. *
  150. * 7) removing row which becomes free due to redundant bounds;
  151. *
  152. * 8) computing implied bounds for all columns in the row and using
  153. * them to strengthen current column bounds (MIP only, optional,
  154. * performed if the flag hard is on).
  155. *
  156. * Additionally the routine may activate affected rows and/or columns
  157. * for further processing.
  158. *
  159. * RETURNS
  160. *
  161. * 0 success;
  162. *
  163. * GLP_ENOPFS primal/integer infeasibility detected;
  164. *
  165. * GLP_ENODFS dual infeasibility detected. */
  166. int npp_process_row(NPP *npp, NPPROW *row, int hard)
  167. { /* perform basic row processing */
  168. NPPCOL *col;
  169. NPPAIJ *aij, *next_aij, *aaa;
  170. int ret;
  171. /* row must not be free */
  172. xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
  173. /* start processing row */
  174. if (row->ptr == NULL)
  175. { /* empty row */
  176. ret = npp_empty_row(npp, row);
  177. if (ret == 0)
  178. { /* row was deleted */
  179. #ifdef GLP_DEBUG
  180. xprintf("A");
  181. #endif
  182. return 0;
  183. }
  184. else if (ret == 1)
  185. { /* primal infeasibility */
  186. return GLP_ENOPFS;
  187. }
  188. else
  189. xassert(ret != ret);
  190. }
  191. if (row->ptr->r_next == NULL)
  192. { /* row singleton */
  193. col = row->ptr->col;
  194. if (row->lb == row->ub)
  195. { /* equality constraint */
  196. ret = npp_eq_singlet(npp, row);
  197. if (ret == 0)
  198. { /* column was fixed, row was deleted */
  199. #ifdef GLP_DEBUG
  200. xprintf("B");
  201. #endif
  202. /* activate rows affected by column */
  203. for (aij = col->ptr; aij != NULL; aij = aij->c_next)
  204. npp_activate_row(npp, aij->row);
  205. /* process fixed column */
  206. npp_fixed_col(npp, col);
  207. /* column was deleted */
  208. return 0;
  209. }
  210. else if (ret == 1 || ret == 2)
  211. { /* primal/integer infeasibility */
  212. return GLP_ENOPFS;
  213. }
  214. else
  215. xassert(ret != ret);
  216. }
  217. else
  218. { /* inequality constraint */
  219. ret = npp_ineq_singlet(npp, row);
  220. if (0 <= ret && ret <= 3)
  221. { /* row was deleted */
  222. #ifdef GLP_DEBUG
  223. xprintf("C");
  224. #endif
  225. /* activate column, since its length was changed due to
  226. row deletion */
  227. npp_activate_col(npp, col);
  228. if (ret >= 2)
  229. { /* column bounds changed significantly or column was
  230. fixed */
  231. /* activate rows affected by column */
  232. for (aij = col->ptr; aij != NULL; aij = aij->c_next)
  233. npp_activate_row(npp, aij->row);
  234. }
  235. if (ret == 3)
  236. { /* column was fixed; process it */
  237. #ifdef GLP_DEBUG
  238. xprintf("D");
  239. #endif
  240. npp_fixed_col(npp, col);
  241. /* column was deleted */
  242. }
  243. return 0;
  244. }
  245. else if (ret == 4)
  246. { /* primal infeasibility */
  247. return GLP_ENOPFS;
  248. }
  249. else
  250. xassert(ret != ret);
  251. }
  252. }
  253. #if 0
  254. /* sometimes this causes too large round-off errors; probably
  255. pivot coefficient should be chosen more carefully */
  256. if (row->ptr->r_next->r_next == NULL)
  257. { /* row doubleton */
  258. if (row->lb == row->ub)
  259. { /* equality constraint */
  260. if (!(row->ptr->col->is_int ||
  261. row->ptr->r_next->col->is_int))
  262. { /* both columns are continuous */
  263. NPPCOL *q;
  264. q = npp_eq_doublet(npp, row);
  265. if (q != NULL)
  266. { /* column q was eliminated */
  267. #ifdef GLP_DEBUG
  268. xprintf("E");
  269. #endif
  270. /* now column q is singleton of type "implied slack
  271. variable"; we process it here to make sure that on
  272. recovering basic solution the row is always active
  273. equality constraint (as required by the routine
  274. rcv_eq_doublet) */
  275. xassert(npp_process_col(npp, q) == 0);
  276. /* column q was deleted; note that row p also may be
  277. deleted */
  278. return 0;
  279. }
  280. }
  281. }
  282. }
  283. #endif
  284. /* general row analysis */
  285. ret = npp_analyze_row(npp, row);
  286. xassert(0x00 <= ret && ret <= 0xFF);
  287. if (ret == 0x33)
  288. { /* row bounds are inconsistent with column bounds */
  289. return GLP_ENOPFS;
  290. }
  291. if ((ret & 0x0F) == 0x00)
  292. { /* row lower bound does not exist or redundant */
  293. if (row->lb != -DBL_MAX)
  294. { /* remove redundant row lower bound */
  295. #ifdef GLP_DEBUG
  296. xprintf("F");
  297. #endif
  298. npp_inactive_bound(npp, row, 0);
  299. }
  300. }
  301. else if ((ret & 0x0F) == 0x01)
  302. { /* row lower bound can be active */
  303. /* see below */
  304. }
  305. else if ((ret & 0x0F) == 0x02)
  306. { /* row lower bound is a forcing bound */
  307. #ifdef GLP_DEBUG
  308. xprintf("G");
  309. #endif
  310. /* process forcing row */
  311. if (npp_forcing_row(npp, row, 0) == 0)
  312. fixup: { /* columns were fixed, row was made free */
  313. for (aij = row->ptr; aij != NULL; aij = next_aij)
  314. { /* process column fixed by forcing row */
  315. #ifdef GLP_DEBUG
  316. xprintf("H");
  317. #endif
  318. col = aij->col;
  319. next_aij = aij->r_next;
  320. /* activate rows affected by column */
  321. for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
  322. npp_activate_row(npp, aaa->row);
  323. /* process fixed column */
  324. npp_fixed_col(npp, col);
  325. /* column was deleted */
  326. }
  327. /* process free row (which now is empty due to deletion of
  328. all its columns) */
  329. npp_free_row(npp, row);
  330. /* row was deleted */
  331. return 0;
  332. }
  333. }
  334. else
  335. xassert(ret != ret);
  336. if ((ret & 0xF0) == 0x00)
  337. { /* row upper bound does not exist or redundant */
  338. if (row->ub != +DBL_MAX)
  339. { /* remove redundant row upper bound */
  340. #ifdef GLP_DEBUG
  341. xprintf("I");
  342. #endif
  343. npp_inactive_bound(npp, row, 1);
  344. }
  345. }
  346. else if ((ret & 0xF0) == 0x10)
  347. { /* row upper bound can be active */
  348. /* see below */
  349. }
  350. else if ((ret & 0xF0) == 0x20)
  351. { /* row upper bound is a forcing bound */
  352. #ifdef GLP_DEBUG
  353. xprintf("J");
  354. #endif
  355. /* process forcing row */
  356. if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
  357. }
  358. else
  359. xassert(ret != ret);
  360. if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
  361. { /* row became free due to redundant bounds removal */
  362. #ifdef GLP_DEBUG
  363. xprintf("K");
  364. #endif
  365. /* activate its columns, since their length will change due
  366. to row deletion */
  367. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  368. npp_activate_col(npp, aij->col);
  369. /* process free row */
  370. npp_free_row(npp, row);
  371. /* row was deleted */
  372. return 0;
  373. }
  374. #if 1 /* 23/XII-2009 */
  375. /* row lower and/or upper bounds can be active */
  376. if (npp->sol == GLP_MIP && hard)
  377. { /* improve current column bounds (optional) */
  378. if (npp_improve_bounds(npp, row, 1) < 0)
  379. return GLP_ENOPFS;
  380. }
  381. #endif
  382. return 0;
  383. }
  384. /***********************************************************************
  385. * NAME
  386. *
  387. * npp_improve_bounds - improve current column bounds
  388. *
  389. * SYNOPSIS
  390. *
  391. * #include "glpnpp.h"
  392. * int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
  393. *
  394. * DESCRIPTION
  395. *
  396. * The routine npp_improve_bounds analyzes specified row (inequality
  397. * or equality constraint) to determine implied column bounds and then
  398. * uses these bounds to improve (strengthen) current column bounds.
  399. *
  400. * If the flag is on and current column bounds changed significantly
  401. * or the column was fixed, the routine activate rows affected by the
  402. * column for further processing. (This feature is intended to be used
  403. * in the main loop of the routine npp_process_row.)
  404. *
  405. * NOTE: This operation can be used for MIP problem only.
  406. *
  407. * RETURNS
  408. *
  409. * The routine npp_improve_bounds returns the number of significantly
  410. * changed bounds plus the number of column having been fixed due to
  411. * bound improvements. However, if the routine detects primal/integer
  412. * infeasibility, it returns a negative value. */
  413. int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
  414. { /* improve current column bounds */
  415. NPPCOL *col;
  416. NPPAIJ *aij, *next_aij, *aaa;
  417. int kase, ret, count = 0;
  418. double lb, ub;
  419. xassert(npp->sol == GLP_MIP);
  420. /* row must not be free */
  421. xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
  422. /* determine implied column bounds */
  423. npp_implied_bounds(npp, row);
  424. /* and use these bounds to strengthen current column bounds */
  425. for (aij = row->ptr; aij != NULL; aij = next_aij)
  426. { col = aij->col;
  427. next_aij = aij->r_next;
  428. for (kase = 0; kase <= 1; kase++)
  429. { /* save current column bounds */
  430. lb = col->lb, ub = col->ub;
  431. if (kase == 0)
  432. { /* process implied column lower bound */
  433. if (col->ll.ll == -DBL_MAX) continue;
  434. ret = npp_implied_lower(npp, col, col->ll.ll);
  435. }
  436. else
  437. { /* process implied column upper bound */
  438. if (col->uu.uu == +DBL_MAX) continue;
  439. ret = npp_implied_upper(npp, col, col->uu.uu);
  440. }
  441. if (ret == 0 || ret == 1)
  442. { /* current column bounds did not change or changed, but
  443. not significantly; restore current column bounds */
  444. col->lb = lb, col->ub = ub;
  445. }
  446. else if (ret == 2 || ret == 3)
  447. { /* current column bounds changed significantly or column
  448. was fixed */
  449. #ifdef GLP_DEBUG
  450. xprintf("L");
  451. #endif
  452. count++;
  453. /* activate other rows affected by column, if required */
  454. if (flag)
  455. { for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
  456. { if (aaa->row != row)
  457. npp_activate_row(npp, aaa->row);
  458. }
  459. }
  460. if (ret == 3)
  461. { /* process fixed column */
  462. #ifdef GLP_DEBUG
  463. xprintf("M");
  464. #endif
  465. npp_fixed_col(npp, col);
  466. /* column was deleted */
  467. break; /* for kase */
  468. }
  469. }
  470. else if (ret == 4)
  471. { /* primal/integer infeasibility */
  472. return -1;
  473. }
  474. else
  475. xassert(ret != ret);
  476. }
  477. }
  478. return count;
  479. }
  480. /***********************************************************************
  481. * NAME
  482. *
  483. * npp_process_col - perform basic column processing
  484. *
  485. * SYNOPSIS
  486. *
  487. * #include "glpnpp.h"
  488. * int npp_process_col(NPP *npp, NPPCOL *col);
  489. *
  490. * DESCRIPTION
  491. *
  492. * The routine npp_process_col performs basic column processing that
  493. * currently includes:
  494. *
  495. * 1) fixing and removing empty column;
  496. *
  497. * 2) removing column singleton, which is implied slack variable, and
  498. * corresponding row if it becomes free;
  499. *
  500. * 3) removing bounds of column, which is implied free variable, and
  501. * replacing corresponding row by equality constraint.
  502. *
  503. * Additionally the routine may activate affected rows and/or columns
  504. * for further processing.
  505. *
  506. * RETURNS
  507. *
  508. * 0 success;
  509. *
  510. * GLP_ENOPFS primal/integer infeasibility detected;
  511. *
  512. * GLP_ENODFS dual infeasibility detected. */
  513. int npp_process_col(NPP *npp, NPPCOL *col)
  514. { /* perform basic column processing */
  515. NPPROW *row;
  516. NPPAIJ *aij;
  517. int ret;
  518. /* column must not be fixed */
  519. xassert(col->lb < col->ub);
  520. /* start processing column */
  521. if (col->ptr == NULL)
  522. { /* empty column */
  523. ret = npp_empty_col(npp, col);
  524. if (ret == 0)
  525. { /* column was fixed and deleted */
  526. #ifdef GLP_DEBUG
  527. xprintf("N");
  528. #endif
  529. return 0;
  530. }
  531. else if (ret == 1)
  532. { /* dual infeasibility */
  533. return GLP_ENODFS;
  534. }
  535. else
  536. xassert(ret != ret);
  537. }
  538. if (col->ptr->c_next == NULL)
  539. { /* column singleton */
  540. row = col->ptr->row;
  541. if (row->lb == row->ub)
  542. { /* equality constraint */
  543. if (!col->is_int)
  544. slack: { /* implied slack variable */
  545. #ifdef GLP_DEBUG
  546. xprintf("O");
  547. #endif
  548. npp_implied_slack(npp, col);
  549. /* column was deleted */
  550. if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
  551. { /* row became free due to implied slack variable */
  552. #ifdef GLP_DEBUG
  553. xprintf("P");
  554. #endif
  555. /* activate columns affected by row */
  556. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  557. npp_activate_col(npp, aij->col);
  558. /* process free row */
  559. npp_free_row(npp, row);
  560. /* row was deleted */
  561. }
  562. else
  563. { /* row became inequality constraint; activate it
  564. since its length changed due to column deletion */
  565. npp_activate_row(npp, row);
  566. }
  567. return 0;
  568. }
  569. }
  570. else
  571. { /* inequality constraint */
  572. if (!col->is_int)
  573. { ret = npp_implied_free(npp, col);
  574. if (ret == 0)
  575. { /* implied free variable */
  576. #ifdef GLP_DEBUG
  577. xprintf("Q");
  578. #endif
  579. /* column bounds were removed, row was replaced by
  580. equality constraint */
  581. goto slack;
  582. }
  583. else if (ret == 1)
  584. { /* column is not implied free variable, because its
  585. lower and/or upper bounds can be active */
  586. }
  587. else if (ret == 2)
  588. { /* dual infeasibility */
  589. return GLP_ENODFS;
  590. }
  591. }
  592. }
  593. }
  594. /* column still exists */
  595. return 0;
  596. }
  597. /***********************************************************************
  598. * NAME
  599. *
  600. * npp_process_prob - perform basic LP/MIP processing
  601. *
  602. * SYNOPSIS
  603. *
  604. * #include "glpnpp.h"
  605. * int npp_process_prob(NPP *npp, int hard);
  606. *
  607. * DESCRIPTION
  608. *
  609. * The routine npp_process_prob performs basic LP/MIP processing that
  610. * currently includes:
  611. *
  612. * 1) initial LP/MIP processing (see the routine npp_clean_prob),
  613. *
  614. * 2) basic row processing (see the routine npp_process_row), and
  615. *
  616. * 3) basic column processing (see the routine npp_process_col).
  617. *
  618. * If the flag hard is on, the routine attempts to improve current
  619. * column bounds multiple times within the main processing loop, in
  620. * which case this feature may take a time. Otherwise, if the flag hard
  621. * is off, improving column bounds is performed only once at the end of
  622. * the main loop. (Note that this feature is used for MIP only.)
  623. *
  624. * The routine uses two sets: the set of active rows and the set of
  625. * active columns. Rows/columns are marked by a flag (the field temp in
  626. * NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
  627. * in which case it is placed in the beginning of the row/column list;
  628. * otherwise, if the flag is zero, the row/column is inactive, in which
  629. * case it is placed in the end of the row/column list. If a row/column
  630. * being currently processed may affect other rows/columns, the latters
  631. * are activated for further processing.
  632. *
  633. * RETURNS
  634. *
  635. * 0 success;
  636. *
  637. * GLP_ENOPFS primal/integer infeasibility detected;
  638. *
  639. * GLP_ENODFS dual infeasibility detected. */
  640. int npp_process_prob(NPP *npp, int hard)
  641. { /* perform basic LP/MIP processing */
  642. NPPROW *row;
  643. NPPCOL *col;
  644. int processing, ret;
  645. /* perform initial LP/MIP processing */
  646. npp_clean_prob(npp);
  647. /* activate all remaining rows and columns */
  648. for (row = npp->r_head; row != NULL; row = row->next)
  649. row->temp = 1;
  650. for (col = npp->c_head; col != NULL; col = col->next)
  651. col->temp = 1;
  652. /* main processing loop */
  653. processing = 1;
  654. while (processing)
  655. { processing = 0;
  656. /* process all active rows */
  657. for (;;)
  658. { row = npp->r_head;
  659. if (row == NULL || !row->temp) break;
  660. npp_deactivate_row(npp, row);
  661. ret = npp_process_row(npp, row, hard);
  662. if (ret != 0) goto done;
  663. processing = 1;
  664. }
  665. /* process all active columns */
  666. for (;;)
  667. { col = npp->c_head;
  668. if (col == NULL || !col->temp) break;
  669. npp_deactivate_col(npp, col);
  670. ret = npp_process_col(npp, col);
  671. if (ret != 0) goto done;
  672. processing = 1;
  673. }
  674. }
  675. #if 1 /* 23/XII-2009 */
  676. if (npp->sol == GLP_MIP && !hard)
  677. { /* improve current column bounds (optional) */
  678. for (row = npp->r_head; row != NULL; row = row->next)
  679. { if (npp_improve_bounds(npp, row, 0) < 0)
  680. { ret = GLP_ENOPFS;
  681. goto done;
  682. }
  683. }
  684. }
  685. #endif
  686. /* all seems ok */
  687. ret = 0;
  688. done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
  689. #ifdef GLP_DEBUG
  690. xprintf("\n");
  691. #endif
  692. return ret;
  693. }
  694. /**********************************************************************/
  695. int npp_simplex(NPP *npp, const glp_smcp *parm)
  696. { /* process LP prior to applying primal/dual simplex method */
  697. int ret;
  698. xassert(npp->sol == GLP_SOL);
  699. xassert(parm == parm);
  700. ret = npp_process_prob(npp, 0);
  701. return ret;
  702. }
  703. /**********************************************************************/
  704. int npp_integer(NPP *npp, const glp_iocp *parm)
  705. { /* process MIP prior to applying branch-and-bound method */
  706. NPPROW *row, *prev_row;
  707. NPPCOL *col;
  708. NPPAIJ *aij;
  709. int count, ret;
  710. xassert(npp->sol == GLP_MIP);
  711. xassert(parm == parm);
  712. /*==============================================================*/
  713. /* perform basic MIP processing */
  714. ret = npp_process_prob(npp, 1);
  715. if (ret != 0) goto done;
  716. /*==============================================================*/
  717. /* binarize problem, if required */
  718. if (parm->binarize)
  719. npp_binarize_prob(npp);
  720. /*==============================================================*/
  721. /* identify hidden packing inequalities */
  722. count = 0;
  723. /* new rows will be added to the end of the row list, so we go
  724. from the end to beginning of the row list */
  725. for (row = npp->r_tail; row != NULL; row = prev_row)
  726. { prev_row = row->prev;
  727. /* skip free row */
  728. if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
  729. /* skip equality constraint */
  730. if (row->lb == row->ub) continue;
  731. /* skip row having less than two variables */
  732. if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
  733. /* skip row having non-binary variables */
  734. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  735. { col = aij->col;
  736. if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
  737. break;
  738. }
  739. if (aij != NULL) continue;
  740. count += npp_hidden_packing(npp, row);
  741. }
  742. if (count > 0)
  743. xprintf("%d hidden packing inequaliti(es) were detected\n",
  744. count);
  745. /*==============================================================*/
  746. /* identify hidden covering inequalities */
  747. count = 0;
  748. /* new rows will be added to the end of the row list, so we go
  749. from the end to beginning of the row list */
  750. for (row = npp->r_tail; row != NULL; row = prev_row)
  751. { prev_row = row->prev;
  752. /* skip free row */
  753. if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
  754. /* skip equality constraint */
  755. if (row->lb == row->ub) continue;
  756. /* skip row having less than three variables */
  757. if (row->ptr == NULL || row->ptr->r_next == NULL ||
  758. row->ptr->r_next->r_next == NULL) continue;
  759. /* skip row having non-binary variables */
  760. for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  761. { col = aij->col;
  762. if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
  763. break;
  764. }
  765. if (aij != NULL) continue;
  766. count += npp_hidden_covering(npp, row);
  767. }
  768. if (count > 0)
  769. xprintf("%d hidden covering inequaliti(es) were detected\n",
  770. count);
  771. /*==============================================================*/
  772. /* reduce inequality constraint coefficients */
  773. count = 0;
  774. /* new rows will be added to the end of the row list, so we go
  775. from the end to beginning of the row list */
  776. for (row = npp->r_tail; row != NULL; row = prev_row)
  777. { prev_row = row->prev;
  778. /* skip equality constraint */
  779. if (row->lb == row->ub) continue;
  780. count += npp_reduce_ineq_coef(npp, row);
  781. }
  782. if (count > 0)
  783. xprintf("%d constraint coefficient(s) were reduced\n", count);
  784. /*==============================================================*/
  785. #ifdef GLP_DEBUG
  786. routine(npp);
  787. #endif
  788. /*==============================================================*/
  789. /* all seems ok */
  790. ret = 0;
  791. done: return ret;
  792. }
  793. /* eof */