aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/glpk-4.65/src/npp
diff options
context:
space:
mode:
authorDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2020-03-03 08:17:40 +0100
committerDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2020-03-03 08:17:40 +0100
commit1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68 (patch)
tree210ffc156c83f04fb0c61a40b4f9037d7ba8a7e1 /test/monniaux/glpk-4.65/src/npp
parent222c9047d61961db9c6b19fed5ca49829223fd33 (diff)
parent12be46d59a2483a10d77fa8ee67f7e0ca1bd702f (diff)
downloadcompcert-kvx-1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68.tar.gz
compcert-kvx-1ab7b51c30e1b10ac45b0bd64cefdc01da0f7f68.zip
Merge branch 'mppa-cse2' of gricad-gitlab.univ-grenoble-alpes.fr:sixcy/CompCert into mppa-work
Diffstat (limited to 'test/monniaux/glpk-4.65/src/npp')
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp.h645
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp1.c937
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp2.c1433
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp3.c2861
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp4.c1414
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp5.c809
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp6.c1500
7 files changed, 9599 insertions, 0 deletions
diff --git a/test/monniaux/glpk-4.65/src/npp/npp.h b/test/monniaux/glpk-4.65/src/npp/npp.h
new file mode 100644
index 00000000..428cb23c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp.h
@@ -0,0 +1,645 @@
+/* npp.h (LP/MIP preprocessor) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef NPP_H
+#define NPP_H
+
+#include "prob.h"
+
+#if 0 /* 20/XI-2017 */
+typedef struct NPP NPP;
+#else
+typedef struct glp_prep NPP;
+#endif
+typedef struct NPPROW NPPROW;
+typedef struct NPPCOL NPPCOL;
+typedef struct NPPAIJ NPPAIJ;
+typedef struct NPPTSE NPPTSE;
+typedef struct NPPLFE NPPLFE;
+
+#if 0 /* 20/XI-2017 */
+struct NPP
+#else
+struct glp_prep
+#endif
+{ /* LP/MIP preprocessor workspace */
+ /*--------------------------------------------------------------*/
+ /* original problem segment */
+ int orig_dir;
+ /* optimization direction flag:
+ GLP_MIN - minimization
+ GLP_MAX - maximization */
+ int orig_m;
+ /* number of rows */
+ int orig_n;
+ /* number of columns */
+ int orig_nnz;
+ /* number of non-zero constraint coefficients */
+ /*--------------------------------------------------------------*/
+ /* transformed problem segment (always minimization) */
+ DMP *pool;
+ /* memory pool to store problem components */
+ char *name;
+ /* problem name (1 to 255 chars); NULL means no name is assigned
+ to the problem */
+ char *obj;
+ /* objective function name (1 to 255 chars); NULL means no name
+ is assigned to the objective function */
+ double c0;
+ /* constant term of the objective function */
+ int nrows;
+ /* number of rows introduced into the problem; this count
+ increases by one every time a new row is added and never
+ decreases; thus, actual number of rows may be less than nrows
+ due to row deletions */
+ int ncols;
+ /* number of columns introduced into the problem; this count
+ increases by one every time a new column is added and never
+ decreases; thus, actual number of column may be less than
+ ncols due to column deletions */
+ NPPROW *r_head;
+ /* pointer to the beginning of the row list */
+ NPPROW *r_tail;
+ /* pointer to the end of the row list */
+ NPPCOL *c_head;
+ /* pointer to the beginning of the column list */
+ NPPCOL *c_tail;
+ /* pointer to the end of the column list */
+ /*--------------------------------------------------------------*/
+ /* transformation history */
+ DMP *stack;
+ /* memory pool to store transformation entries */
+ NPPTSE *top;
+ /* pointer to most recent transformation entry */
+#if 0 /* 16/XII-2009 */
+ int count[1+25];
+ /* transformation statistics */
+#endif
+ /*--------------------------------------------------------------*/
+ /* resultant (preprocessed) problem segment */
+ int m;
+ /* number of rows */
+ int n;
+ /* number of columns */
+ int nnz;
+ /* number of non-zero constraint coefficients */
+ int *row_ref; /* int row_ref[1+m]; */
+ /* row_ref[i], 1 <= i <= m, is the reference number assigned to
+ a row, which is i-th row of the resultant problem */
+ int *col_ref; /* int col_ref[1+n]; */
+ /* col_ref[j], 1 <= j <= n, is the reference number assigned to
+ a column, which is j-th column of the resultant problem */
+ /*--------------------------------------------------------------*/
+ /* recovered solution segment */
+ int sol;
+ /* solution indicator:
+ GLP_SOL - basic solution
+ GLP_IPT - interior-point solution
+ GLP_MIP - mixed integer solution */
+ int scaling;
+ /* scaling option:
+ GLP_OFF - scaling is disabled
+ GLP_ON - scaling is enabled */
+ int p_stat;
+ /* status of primal basic solution:
+ GLP_UNDEF - primal solution is undefined
+ GLP_FEAS - primal solution is feasible
+ GLP_INFEAS - primal solution is infeasible
+ GLP_NOFEAS - no primal feasible solution exists */
+ int d_stat;
+ /* status of dual basic solution:
+ GLP_UNDEF - dual solution is undefined
+ GLP_FEAS - dual solution is feasible
+ GLP_INFEAS - dual solution is infeasible
+ GLP_NOFEAS - no dual feasible solution exists */
+ int t_stat;
+ /* status of interior-point solution:
+ GLP_UNDEF - interior solution is undefined
+ GLP_OPT - interior solution is optimal */
+ int i_stat;
+ /* status of mixed integer solution:
+ GLP_UNDEF - integer solution is undefined
+ GLP_OPT - integer solution is optimal
+ GLP_FEAS - integer solution is feasible
+ GLP_NOFEAS - no integer solution exists */
+ char *r_stat; /* char r_stat[1+nrows]; */
+ /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
+ GLP_BS - inactive constraint
+ GLP_NL - active constraint on lower bound
+ GLP_NU - active constraint on upper bound
+ GLP_NF - active free row
+ GLP_NS - active equality constraint */
+ char *c_stat; /* char c_stat[1+nrows]; */
+ /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
+ GLP_BS - basic variable
+ GLP_NL - non-basic variable on lower bound
+ GLP_NU - non-basic variable on upper bound
+ GLP_NF - non-basic free variable
+ GLP_NS - non-basic fixed variable */
+ double *r_pi; /* double r_pi[1+nrows]; */
+ /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
+ for i-th row (constraint) */
+ double *c_value; /* double c_value[1+ncols]; */
+ /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
+ (structural variable) */
+};
+
+struct NPPROW
+{ /* row (constraint) */
+ int i;
+ /* reference number assigned to the row, 1 <= i <= nrows */
+ char *name;
+ /* row name (1 to 255 chars); NULL means no name is assigned to
+ the row */
+ double lb;
+ /* lower bound; -DBL_MAX means the row has no lower bound */
+ double ub;
+ /* upper bound; +DBL_MAX means the row has no upper bound */
+ NPPAIJ *ptr;
+ /* pointer to the linked list of constraint coefficients */
+ int temp;
+ /* working field used by preprocessor routines */
+ NPPROW *prev;
+ /* pointer to previous row in the row list */
+ NPPROW *next;
+ /* pointer to next row in the row list */
+};
+
+struct NPPCOL
+{ /* column (variable) */
+ int j;
+ /* reference number assigned to the column, 1 <= j <= ncols */
+ char *name;
+ /* column name (1 to 255 chars); NULL means no name is assigned
+ to the column */
+ char is_int;
+ /* 0 means continuous variable; 1 means integer variable */
+ double lb;
+ /* lower bound; -DBL_MAX means the column has no lower bound */
+ double ub;
+ /* upper bound; +DBL_MAX means the column has no upper bound */
+ double coef;
+ /* objective coefficient */
+ NPPAIJ *ptr;
+ /* pointer to the linked list of constraint coefficients */
+ int temp;
+ /* working field used by preprocessor routines */
+#if 1 /* 28/XII-2009 */
+ union
+ { double ll;
+ /* implied column lower bound */
+ int pos;
+ /* vertex ordinal number corresponding to this binary column
+ in the conflict graph (0, if the vertex does not exist) */
+ } ll;
+ union
+ { double uu;
+ /* implied column upper bound */
+ int neg;
+ /* vertex ordinal number corresponding to complement of this
+ binary column in the conflict graph (0, if the vertex does
+ not exist) */
+ } uu;
+#endif
+ NPPCOL *prev;
+ /* pointer to previous column in the column list */
+ NPPCOL *next;
+ /* pointer to next column in the column list */
+};
+
+struct NPPAIJ
+{ /* constraint coefficient */
+ NPPROW *row;
+ /* pointer to corresponding row */
+ NPPCOL *col;
+ /* pointer to corresponding column */
+ double val;
+ /* (non-zero) coefficient value */
+ NPPAIJ *r_prev;
+ /* pointer to previous coefficient in the same row */
+ NPPAIJ *r_next;
+ /* pointer to next coefficient in the same row */
+ NPPAIJ *c_prev;
+ /* pointer to previous coefficient in the same column */
+ NPPAIJ *c_next;
+ /* pointer to next coefficient in the same column */
+};
+
+struct NPPTSE
+{ /* transformation stack entry */
+ int (*func)(NPP *npp, void *info);
+ /* pointer to routine performing back transformation */
+ void *info;
+ /* pointer to specific info (depends on the transformation) */
+ NPPTSE *link;
+ /* pointer to another entry created *before* this entry */
+};
+
+struct NPPLFE
+{ /* linear form element */
+ int ref;
+ /* row/column reference number */
+ double val;
+ /* (non-zero) coefficient value */
+ NPPLFE *next;
+ /* pointer to another element */
+};
+
+#define npp_create_wksp _glp_npp_create_wksp
+NPP *npp_create_wksp(void);
+/* create LP/MIP preprocessor workspace */
+
+#define npp_insert_row _glp_npp_insert_row
+void npp_insert_row(NPP *npp, NPPROW *row, int where);
+/* insert row to the row list */
+
+#define npp_remove_row _glp_npp_remove_row
+void npp_remove_row(NPP *npp, NPPROW *row);
+/* remove row from the row list */
+
+#define npp_activate_row _glp_npp_activate_row
+void npp_activate_row(NPP *npp, NPPROW *row);
+/* make row active */
+
+#define npp_deactivate_row _glp_npp_deactivate_row
+void npp_deactivate_row(NPP *npp, NPPROW *row);
+/* make row inactive */
+
+#define npp_insert_col _glp_npp_insert_col
+void npp_insert_col(NPP *npp, NPPCOL *col, int where);
+/* insert column to the column list */
+
+#define npp_remove_col _glp_npp_remove_col
+void npp_remove_col(NPP *npp, NPPCOL *col);
+/* remove column from the column list */
+
+#define npp_activate_col _glp_npp_activate_col
+void npp_activate_col(NPP *npp, NPPCOL *col);
+/* make column active */
+
+#define npp_deactivate_col _glp_npp_deactivate_col
+void npp_deactivate_col(NPP *npp, NPPCOL *col);
+/* make column inactive */
+
+#define npp_add_row _glp_npp_add_row
+NPPROW *npp_add_row(NPP *npp);
+/* add new row to the current problem */
+
+#define npp_add_col _glp_npp_add_col
+NPPCOL *npp_add_col(NPP *npp);
+/* add new column to the current problem */
+
+#define npp_add_aij _glp_npp_add_aij
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
+/* add new element to the constraint matrix */
+
+#define npp_row_nnz _glp_npp_row_nnz
+int npp_row_nnz(NPP *npp, NPPROW *row);
+/* count number of non-zero coefficients in row */
+
+#define npp_col_nnz _glp_npp_col_nnz
+int npp_col_nnz(NPP *npp, NPPCOL *col);
+/* count number of non-zero coefficients in column */
+
+#define npp_push_tse _glp_npp_push_tse
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+ int size);
+/* push new entry to the transformation stack */
+
+#define npp_erase_row _glp_npp_erase_row
+void npp_erase_row(NPP *npp, NPPROW *row);
+/* erase row content to make it empty */
+
+#define npp_del_row _glp_npp_del_row
+void npp_del_row(NPP *npp, NPPROW *row);
+/* remove row from the current problem */
+
+#define npp_del_col _glp_npp_del_col
+void npp_del_col(NPP *npp, NPPCOL *col);
+/* remove column from the current problem */
+
+#define npp_del_aij _glp_npp_del_aij
+void npp_del_aij(NPP *npp, NPPAIJ *aij);
+/* remove element from the constraint matrix */
+
+#define npp_load_prob _glp_npp_load_prob
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+ int scaling);
+/* load original problem into the preprocessor workspace */
+
+#define npp_build_prob _glp_npp_build_prob
+void npp_build_prob(NPP *npp, glp_prob *prob);
+/* build resultant (preprocessed) problem */
+
+#define npp_postprocess _glp_npp_postprocess
+void npp_postprocess(NPP *npp, glp_prob *prob);
+/* postprocess solution from the resultant problem */
+
+#define npp_unload_sol _glp_npp_unload_sol
+void npp_unload_sol(NPP *npp, glp_prob *orig);
+/* store solution to the original problem */
+
+#define npp_delete_wksp _glp_npp_delete_wksp
+void npp_delete_wksp(NPP *npp);
+/* delete LP/MIP preprocessor workspace */
+
+#define npp_error()
+
+#define npp_free_row _glp_npp_free_row
+void npp_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_geq_row _glp_npp_geq_row
+void npp_geq_row(NPP *npp, NPPROW *p);
+/* process row of 'not less than' type */
+
+#define npp_leq_row _glp_npp_leq_row
+void npp_leq_row(NPP *npp, NPPROW *p);
+/* process row of 'not greater than' type */
+
+#define npp_free_col _glp_npp_free_col
+void npp_free_col(NPP *npp, NPPCOL *q);
+/* process free (unbounded) column */
+
+#define npp_lbnd_col _glp_npp_lbnd_col
+void npp_lbnd_col(NPP *npp, NPPCOL *q);
+/* process column with (non-zero) lower bound */
+
+#define npp_ubnd_col _glp_npp_ubnd_col
+void npp_ubnd_col(NPP *npp, NPPCOL *q);
+/* process column with upper bound */
+
+#define npp_dbnd_col _glp_npp_dbnd_col
+void npp_dbnd_col(NPP *npp, NPPCOL *q);
+/* process non-negative column with upper bound */
+
+#define npp_fixed_col _glp_npp_fixed_col
+void npp_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_make_equality _glp_npp_make_equality
+int npp_make_equality(NPP *npp, NPPROW *p);
+/* process row with almost identical bounds */
+
+#define npp_make_fixed _glp_npp_make_fixed
+int npp_make_fixed(NPP *npp, NPPCOL *q);
+/* process column with almost identical bounds */
+
+#define npp_empty_row _glp_npp_empty_row
+int npp_empty_row(NPP *npp, NPPROW *p);
+/* process empty row */
+
+#define npp_empty_col _glp_npp_empty_col
+int npp_empty_col(NPP *npp, NPPCOL *q);
+/* process empty column */
+
+#define npp_implied_value _glp_npp_implied_value
+int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+/* process implied column value */
+
+#define npp_eq_singlet _glp_npp_eq_singlet
+int npp_eq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (equality constraint) */
+
+#define npp_implied_lower _glp_npp_implied_lower
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+/* process implied column lower bound */
+
+#define npp_implied_upper _glp_npp_implied_upper
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+/* process implied upper bound of column */
+
+#define npp_ineq_singlet _glp_npp_ineq_singlet
+int npp_ineq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (inequality constraint) */
+
+#define npp_implied_slack _glp_npp_implied_slack
+void npp_implied_slack(NPP *npp, NPPCOL *q);
+/* process column singleton (implied slack variable) */
+
+#define npp_implied_free _glp_npp_implied_free
+int npp_implied_free(NPP *npp, NPPCOL *q);
+/* process column singleton (implied free variable) */
+
+#define npp_eq_doublet _glp_npp_eq_doublet
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+/* process row doubleton (equality constraint) */
+
+#define npp_forcing_row _glp_npp_forcing_row
+int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+/* process forcing row */
+
+#define npp_analyze_row _glp_npp_analyze_row
+int npp_analyze_row(NPP *npp, NPPROW *p);
+/* perform general row analysis */
+
+#define npp_inactive_bound _glp_npp_inactive_bound
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+/* remove row lower/upper inactive bound */
+
+#define npp_implied_bounds _glp_npp_implied_bounds
+void npp_implied_bounds(NPP *npp, NPPROW *p);
+/* determine implied column bounds */
+
+#define npp_binarize_prob _glp_npp_binarize_prob
+int npp_binarize_prob(NPP *npp);
+/* binarize MIP problem */
+
+#define npp_is_packing _glp_npp_is_packing
+int npp_is_packing(NPP *npp, NPPROW *row);
+/* test if constraint is packing inequality */
+
+#define npp_hidden_packing _glp_npp_hidden_packing
+int npp_hidden_packing(NPP *npp, NPPROW *row);
+/* identify hidden packing inequality */
+
+#define npp_implied_packing _glp_npp_implied_packing
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+ NPPCOL *var[], char set[]);
+/* identify implied packing inequality */
+
+#define npp_is_covering _glp_npp_is_covering
+int npp_is_covering(NPP *npp, NPPROW *row);
+/* test if constraint is covering inequality */
+
+#define npp_hidden_covering _glp_npp_hidden_covering
+int npp_hidden_covering(NPP *npp, NPPROW *row);
+/* identify hidden covering inequality */
+
+#define npp_is_partitioning _glp_npp_is_partitioning
+int npp_is_partitioning(NPP *npp, NPPROW *row);
+/* test if constraint is partitioning equality */
+
+#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+/* reduce inequality constraint coefficients */
+
+#define npp_clean_prob _glp_npp_clean_prob
+void npp_clean_prob(NPP *npp);
+/* perform initial LP/MIP processing */
+
+#define npp_process_row _glp_npp_process_row
+int npp_process_row(NPP *npp, NPPROW *row, int hard);
+/* perform basic row processing */
+
+#define npp_improve_bounds _glp_npp_improve_bounds
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+/* improve current column bounds */
+
+#define npp_process_col _glp_npp_process_col
+int npp_process_col(NPP *npp, NPPCOL *col);
+/* perform basic column processing */
+
+#define npp_process_prob _glp_npp_process_prob
+int npp_process_prob(NPP *npp, int hard);
+/* perform basic LP/MIP processing */
+
+#define npp_simplex _glp_npp_simplex
+int npp_simplex(NPP *npp, const glp_smcp *parm);
+/* process LP prior to applying primal/dual simplex method */
+
+#define npp_integer _glp_npp_integer
+int npp_integer(NPP *npp, const glp_iocp *parm);
+/* process MIP prior to applying branch-and-bound method */
+
+/**********************************************************************/
+
+#define npp_sat_free_row _glp_npp_sat_free_row
+void npp_sat_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_sat_fixed_col _glp_npp_sat_fixed_col
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_sat_is_bin_comb _glp_npp_sat_is_bin_comb
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row);
+/* test if row is binary combination */
+
+#define npp_sat_num_pos_coef _glp_npp_sat_num_pos_coef
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row);
+/* determine number of positive coefficients */
+
+#define npp_sat_num_neg_coef _glp_npp_sat_num_neg_coef
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row);
+/* determine number of negative coefficients */
+
+#define npp_sat_is_cover_ineq _glp_npp_sat_is_cover_ineq
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row);
+/* test if row is covering inequality */
+
+#define npp_sat_is_pack_ineq _glp_npp_sat_is_pack_ineq
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row);
+/* test if row is packing inequality */
+
+#define npp_sat_is_partn_eq _glp_npp_sat_is_partn_eq
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row);
+/* test if row is partitioning equality */
+
+#define npp_sat_reverse_row _glp_npp_sat_reverse_row
+int npp_sat_reverse_row(NPP *npp, NPPROW *row);
+/* multiply both sides of row by -1 */
+
+#define npp_sat_split_pack _glp_npp_sat_split_pack
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nnn);
+/* split packing inequality */
+
+#define npp_sat_encode_pack _glp_npp_sat_encode_pack
+void npp_sat_encode_pack(NPP *npp, NPPROW *row);
+/* encode packing inequality */
+
+typedef struct NPPLIT NPPLIT;
+typedef struct NPPLSE NPPLSE;
+typedef struct NPPSED NPPSED;
+
+struct NPPLIT
+{ /* literal (binary variable or its negation) */
+ NPPCOL *col;
+ /* pointer to binary variable; NULL means constant false */
+ int neg;
+ /* negation flag:
+ 0 - literal is variable (or constant false)
+ 1 - literal is negation of variable (or constant true) */
+};
+
+struct NPPLSE
+{ /* literal set element */
+ NPPLIT lit;
+ /* literal */
+ NPPLSE *next;
+ /* pointer to another element */
+};
+
+struct NPPSED
+{ /* summation encoding descriptor */
+ /* this struct describes the equality
+ x + y + z = s + 2 * c,
+ which was encoded as CNF and included into the transformed
+ problem; here x and y are literals, z is either a literal or
+ constant zero, s and c are binary variables modeling, resp.,
+ the low and high (carry) sum bits */
+ NPPLIT x, y, z;
+ /* literals; if z.col = NULL, z is constant zero */
+ NPPCOL *s, *c;
+ /* binary variables modeling the sum bits */
+};
+
+#define npp_sat_encode_sum2 _glp_npp_sat_encode_sum2
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 2-bit summation */
+
+#define npp_sat_encode_sum3 _glp_npp_sat_encode_sum3
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 3-bit summation */
+
+#define npp_sat_encode_sum_ax _glp_npp_sat_encode_sum_ax
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[]);
+/* encode linear combination of 0-1 variables */
+
+#define npp_sat_normalize_clause _glp_npp_sat_normalize_clause
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[]);
+/* normalize clause */
+
+#define npp_sat_encode_clause _glp_npp_sat_encode_clause
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[]);
+/* translate clause to cover inequality */
+
+#define npp_sat_encode_geq _glp_npp_sat_encode_geq
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not less than" constraint */
+
+#define npp_sat_encode_leq _glp_npp_sat_encode_leq
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not greater than" constraint */
+
+#define npp_sat_encode_row _glp_npp_sat_encode_row
+int npp_sat_encode_row(NPP *npp, NPPROW *row);
+/* encode constraint (row) of general type */
+
+#define npp_sat_encode_prob _glp_npp_sat_encode_prob
+int npp_sat_encode_prob(NPP *npp);
+/* encode 0-1 feasibility problem */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp1.c b/test/monniaux/glpk-4.65/src/npp/npp1.c
new file mode 100644
index 00000000..51758bad
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp1.c
@@ -0,0 +1,937 @@
+/* npp1.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+NPP *npp_create_wksp(void)
+{ /* create LP/MIP preprocessor workspace */
+ NPP *npp;
+ npp = xmalloc(sizeof(NPP));
+ npp->orig_dir = 0;
+ npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
+ npp->pool = dmp_create_pool();
+ npp->name = npp->obj = NULL;
+ npp->c0 = 0.0;
+ npp->nrows = npp->ncols = 0;
+ npp->r_head = npp->r_tail = NULL;
+ npp->c_head = npp->c_tail = NULL;
+ npp->stack = dmp_create_pool();
+ npp->top = NULL;
+#if 0 /* 16/XII-2009 */
+ memset(&npp->count, 0, sizeof(npp->count));
+#endif
+ npp->m = npp->n = npp->nnz = 0;
+ npp->row_ref = npp->col_ref = NULL;
+ npp->sol = npp->scaling = 0;
+ npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
+ npp->r_stat = NULL;
+ /*npp->r_prim =*/ npp->r_pi = NULL;
+ npp->c_stat = NULL;
+ npp->c_value = /*npp->c_dual =*/ NULL;
+ return npp;
+}
+
+void npp_insert_row(NPP *npp, NPPROW *row, int where)
+{ /* insert row to the row list */
+ if (where == 0)
+ { /* insert row to the beginning of the row list */
+ row->prev = NULL;
+ row->next = npp->r_head;
+ if (row->next == NULL)
+ npp->r_tail = row;
+ else
+ row->next->prev = row;
+ npp->r_head = row;
+ }
+ else
+ { /* insert row to the end of the row list */
+ row->prev = npp->r_tail;
+ row->next = NULL;
+ if (row->prev == NULL)
+ npp->r_head = row;
+ else
+ row->prev->next = row;
+ npp->r_tail = row;
+ }
+ return;
+}
+
+void npp_remove_row(NPP *npp, NPPROW *row)
+{ /* remove row from the row list */
+ if (row->prev == NULL)
+ npp->r_head = row->next;
+ else
+ row->prev->next = row->next;
+ if (row->next == NULL)
+ npp->r_tail = row->prev;
+ else
+ row->next->prev = row->prev;
+ return;
+}
+
+void npp_activate_row(NPP *npp, NPPROW *row)
+{ /* make row active */
+ if (!row->temp)
+ { row->temp = 1;
+ /* move the row to the beginning of the row list */
+ npp_remove_row(npp, row);
+ npp_insert_row(npp, row, 0);
+ }
+ return;
+}
+
+void npp_deactivate_row(NPP *npp, NPPROW *row)
+{ /* make row inactive */
+ if (row->temp)
+ { row->temp = 0;
+ /* move the row to the end of the row list */
+ npp_remove_row(npp, row);
+ npp_insert_row(npp, row, 1);
+ }
+ return;
+}
+
+void npp_insert_col(NPP *npp, NPPCOL *col, int where)
+{ /* insert column to the column list */
+ if (where == 0)
+ { /* insert column to the beginning of the column list */
+ col->prev = NULL;
+ col->next = npp->c_head;
+ if (col->next == NULL)
+ npp->c_tail = col;
+ else
+ col->next->prev = col;
+ npp->c_head = col;
+ }
+ else
+ { /* insert column to the end of the column list */
+ col->prev = npp->c_tail;
+ col->next = NULL;
+ if (col->prev == NULL)
+ npp->c_head = col;
+ else
+ col->prev->next = col;
+ npp->c_tail = col;
+ }
+ return;
+}
+
+void npp_remove_col(NPP *npp, NPPCOL *col)
+{ /* remove column from the column list */
+ if (col->prev == NULL)
+ npp->c_head = col->next;
+ else
+ col->prev->next = col->next;
+ if (col->next == NULL)
+ npp->c_tail = col->prev;
+ else
+ col->next->prev = col->prev;
+ return;
+}
+
+void npp_activate_col(NPP *npp, NPPCOL *col)
+{ /* make column active */
+ if (!col->temp)
+ { col->temp = 1;
+ /* move the column to the beginning of the column list */
+ npp_remove_col(npp, col);
+ npp_insert_col(npp, col, 0);
+ }
+ return;
+}
+
+void npp_deactivate_col(NPP *npp, NPPCOL *col)
+{ /* make column inactive */
+ if (col->temp)
+ { col->temp = 0;
+ /* move the column to the end of the column list */
+ npp_remove_col(npp, col);
+ npp_insert_col(npp, col, 1);
+ }
+ return;
+}
+
+NPPROW *npp_add_row(NPP *npp)
+{ /* add new row to the current problem */
+ NPPROW *row;
+ row = dmp_get_atom(npp->pool, sizeof(NPPROW));
+ row->i = ++(npp->nrows);
+ row->name = NULL;
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ row->ptr = NULL;
+ row->temp = 0;
+ npp_insert_row(npp, row, 1);
+ return row;
+}
+
+NPPCOL *npp_add_col(NPP *npp)
+{ /* add new column to the current problem */
+ NPPCOL *col;
+ col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
+ col->j = ++(npp->ncols);
+ col->name = NULL;
+#if 0
+ col->kind = GLP_CV;
+#else
+ col->is_int = 0;
+#endif
+ col->lb = col->ub = col->coef = 0.0;
+ col->ptr = NULL;
+ col->temp = 0;
+ npp_insert_col(npp, col, 1);
+ return col;
+}
+
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
+{ /* add new element to the constraint matrix */
+ NPPAIJ *aij;
+ aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
+ aij->row = row;
+ aij->col = col;
+ aij->val = val;
+ aij->r_prev = NULL;
+ aij->r_next = row->ptr;
+ aij->c_prev = NULL;
+ aij->c_next = col->ptr;
+ if (aij->r_next != NULL)
+ aij->r_next->r_prev = aij;
+ if (aij->c_next != NULL)
+ aij->c_next->c_prev = aij;
+ row->ptr = col->ptr = aij;
+ return aij;
+}
+
+int npp_row_nnz(NPP *npp, NPPROW *row)
+{ /* count number of non-zero coefficients in row */
+ NPPAIJ *aij;
+ int nnz;
+ xassert(npp == npp);
+ nnz = 0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ nnz++;
+ return nnz;
+}
+
+int npp_col_nnz(NPP *npp, NPPCOL *col)
+{ /* count number of non-zero coefficients in column */
+ NPPAIJ *aij;
+ int nnz;
+ xassert(npp == npp);
+ nnz = 0;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ nnz++;
+ return nnz;
+}
+
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+ int size)
+{ /* push new entry to the transformation stack */
+ NPPTSE *tse;
+ tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
+ tse->func = func;
+ tse->info = dmp_get_atom(npp->stack, size);
+ tse->link = npp->top;
+ npp->top = tse;
+ return tse->info;
+}
+
+#if 1 /* 23/XII-2009 */
+void npp_erase_row(NPP *npp, NPPROW *row)
+{ /* erase row content to make it empty */
+ NPPAIJ *aij;
+ while (row->ptr != NULL)
+ { aij = row->ptr;
+ row->ptr = aij->r_next;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+ return;
+}
+#endif
+
+void npp_del_row(NPP *npp, NPPROW *row)
+{ /* remove row from the current problem */
+#if 0 /* 23/XII-2009 */
+ NPPAIJ *aij;
+#endif
+ if (row->name != NULL)
+ dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
+#if 0 /* 23/XII-2009 */
+ while (row->ptr != NULL)
+ { aij = row->ptr;
+ row->ptr = aij->r_next;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+#else
+ npp_erase_row(npp, row);
+#endif
+ npp_remove_row(npp, row);
+ dmp_free_atom(npp->pool, row, sizeof(NPPROW));
+ return;
+}
+
+void npp_del_col(NPP *npp, NPPCOL *col)
+{ /* remove column from the current problem */
+ NPPAIJ *aij;
+ if (col->name != NULL)
+ dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
+ while (col->ptr != NULL)
+ { aij = col->ptr;
+ col->ptr = aij->c_next;
+ if (aij->r_prev == NULL)
+ aij->row->ptr = aij->r_next;
+ else
+ aij->r_prev->r_next = aij->r_next;
+ if (aij->r_next == NULL)
+ ;
+ else
+ aij->r_next->r_prev = aij->r_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+ npp_remove_col(npp, col);
+ dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
+ return;
+}
+
+void npp_del_aij(NPP *npp, NPPAIJ *aij)
+{ /* remove element from the constraint matrix */
+ if (aij->r_prev == NULL)
+ aij->row->ptr = aij->r_next;
+ else
+ aij->r_prev->r_next = aij->r_next;
+ if (aij->r_next == NULL)
+ ;
+ else
+ aij->r_next->r_prev = aij->r_prev;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ return;
+}
+
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+ int scaling)
+{ /* load original problem into the preprocessor workspace */
+ int m = orig->m;
+ int n = orig->n;
+ NPPROW **link;
+ int i, j;
+ double dir;
+ xassert(names == GLP_OFF || names == GLP_ON);
+ xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
+ xassert(scaling == GLP_OFF || scaling == GLP_ON);
+ if (sol == GLP_MIP) xassert(!scaling);
+ npp->orig_dir = orig->dir;
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ npp->orig_m = m;
+ npp->orig_n = n;
+ npp->orig_nnz = orig->nnz;
+ if (names && orig->name != NULL)
+ { npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
+ strcpy(npp->name, orig->name);
+ }
+ if (names && orig->obj != NULL)
+ { npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
+ strcpy(npp->obj, orig->obj);
+ }
+ npp->c0 = dir * orig->c0;
+ /* load rows */
+ link = xcalloc(1+m, sizeof(NPPROW *));
+ for (i = 1; i <= m; i++)
+ { GLPROW *rrr = orig->row[i];
+ NPPROW *row;
+ link[i] = row = npp_add_row(npp);
+ xassert(row->i == i);
+ if (names && rrr->name != NULL)
+ { row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
+ strcpy(row->name, rrr->name);
+ }
+ if (!scaling)
+ { if (rrr->type == GLP_FR)
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_LO)
+ row->lb = rrr->lb, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_UP)
+ row->lb = -DBL_MAX, row->ub = rrr->ub;
+ else if (rrr->type == GLP_DB)
+ row->lb = rrr->lb, row->ub = rrr->ub;
+ else if (rrr->type == GLP_FX)
+ row->lb = row->ub = rrr->lb;
+ else
+ xassert(rrr != rrr);
+ }
+ else
+ { double rii = rrr->rii;
+ if (rrr->type == GLP_FR)
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_LO)
+ row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_UP)
+ row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
+ else if (rrr->type == GLP_DB)
+ row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
+ else if (rrr->type == GLP_FX)
+ row->lb = row->ub = rrr->lb * rii;
+ else
+ xassert(rrr != rrr);
+ }
+ }
+ /* load columns and constraint coefficients */
+ for (j = 1; j <= n; j++)
+ { GLPCOL *ccc = orig->col[j];
+ GLPAIJ *aaa;
+ NPPCOL *col;
+ col = npp_add_col(npp);
+ xassert(col->j == j);
+ if (names && ccc->name != NULL)
+ { col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
+ strcpy(col->name, ccc->name);
+ }
+ if (sol == GLP_MIP)
+#if 0
+ col->kind = ccc->kind;
+#else
+ col->is_int = (char)(ccc->kind == GLP_IV);
+#endif
+ if (!scaling)
+ { if (ccc->type == GLP_FR)
+ col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_LO)
+ col->lb = ccc->lb, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_UP)
+ col->lb = -DBL_MAX, col->ub = ccc->ub;
+ else if (ccc->type == GLP_DB)
+ col->lb = ccc->lb, col->ub = ccc->ub;
+ else if (ccc->type == GLP_FX)
+ col->lb = col->ub = ccc->lb;
+ else
+ xassert(ccc != ccc);
+ col->coef = dir * ccc->coef;
+ for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
+ }
+ else
+ { double sjj = ccc->sjj;
+ if (ccc->type == GLP_FR)
+ col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_LO)
+ col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_UP)
+ col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
+ else if (ccc->type == GLP_DB)
+ col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
+ else if (ccc->type == GLP_FX)
+ col->lb = col->ub = ccc->lb / sjj;
+ else
+ xassert(ccc != ccc);
+ col->coef = dir * ccc->coef * sjj;
+ for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_add_aij(npp, link[aaa->row->i], col,
+ aaa->row->rii * aaa->val * sjj);
+ }
+ }
+ xfree(link);
+ /* keep solution indicator and scaling option */
+ npp->sol = sol;
+ npp->scaling = scaling;
+ return;
+}
+
+void npp_build_prob(NPP *npp, glp_prob *prob)
+{ /* build resultant (preprocessed) problem */
+ NPPROW *row;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int i, j, type, len, *ind;
+ double dir, *val;
+ glp_erase_prob(prob);
+ glp_set_prob_name(prob, npp->name);
+ glp_set_obj_name(prob, npp->obj);
+ glp_set_obj_dir(prob, npp->orig_dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ glp_set_obj_coef(prob, 0, dir * npp->c0);
+ /* build rows */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ { row->temp = i = glp_add_rows(prob, 1);
+ glp_set_row_name(prob, i, row->name);
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ type = GLP_FR;
+ else if (row->ub == +DBL_MAX)
+ type = GLP_LO;
+ else if (row->lb == -DBL_MAX)
+ type = GLP_UP;
+ else if (row->lb != row->ub)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_row_bnds(prob, i, type, row->lb, row->ub);
+ }
+ /* build columns and the constraint matrix */
+ ind = xcalloc(1+prob->m, sizeof(int));
+ val = xcalloc(1+prob->m, sizeof(double));
+ for (col = npp->c_head; col != NULL; col = col->next)
+ { j = glp_add_cols(prob, 1);
+ glp_set_col_name(prob, j, col->name);
+#if 0
+ glp_set_col_kind(prob, j, col->kind);
+#else
+ glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
+#endif
+ if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+ type = GLP_FR;
+ else if (col->ub == +DBL_MAX)
+ type = GLP_LO;
+ else if (col->lb == -DBL_MAX)
+ type = GLP_UP;
+ else if (col->lb != col->ub)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(prob, j, type, col->lb, col->ub);
+ glp_set_obj_coef(prob, j, dir * col->coef);
+ len = 0;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ { len++;
+ ind[len] = aij->row->temp;
+ val[len] = aij->val;
+ }
+ glp_set_mat_col(prob, j, len, ind, val);
+ }
+ xfree(ind);
+ xfree(val);
+ /* resultant problem has been built */
+ npp->m = prob->m;
+ npp->n = prob->n;
+ npp->nnz = prob->nnz;
+ npp->row_ref = xcalloc(1+npp->m, sizeof(int));
+ npp->col_ref = xcalloc(1+npp->n, sizeof(int));
+ for (row = npp->r_head, i = 0; row != NULL; row = row->next)
+ npp->row_ref[++i] = row->i;
+ for (col = npp->c_head, j = 0; col != NULL; col = col->next)
+ npp->col_ref[++j] = col->j;
+ /* transformed problem segment is no longer needed */
+ dmp_delete_pool(npp->pool), npp->pool = NULL;
+ npp->name = npp->obj = NULL;
+ npp->c0 = 0.0;
+ npp->r_head = npp->r_tail = NULL;
+ npp->c_head = npp->c_tail = NULL;
+ return;
+}
+
+void npp_postprocess(NPP *npp, glp_prob *prob)
+{ /* postprocess solution from the resultant problem */
+ GLPROW *row;
+ GLPCOL *col;
+ NPPTSE *tse;
+ int i, j, k;
+ double dir;
+ xassert(npp->orig_dir == prob->dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+#if 0 /* 11/VII-2013; due to call from ios_main */
+ xassert(npp->m == prob->m);
+#else
+ if (npp->sol != GLP_MIP)
+ xassert(npp->m == prob->m);
+#endif
+ xassert(npp->n == prob->n);
+#if 0 /* 11/VII-2013; due to call from ios_main */
+ xassert(npp->nnz == prob->nnz);
+#else
+ if (npp->sol != GLP_MIP)
+ xassert(npp->nnz == prob->nnz);
+#endif
+ /* copy solution status */
+ if (npp->sol == GLP_SOL)
+ { npp->p_stat = prob->pbs_stat;
+ npp->d_stat = prob->dbs_stat;
+ }
+ else if (npp->sol == GLP_IPT)
+ npp->t_stat = prob->ipt_stat;
+ else if (npp->sol == GLP_MIP)
+ npp->i_stat = prob->mip_stat;
+ else
+ xassert(npp != npp);
+ /* allocate solution arrays */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat == NULL)
+ npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_stat[i] = 0;
+ if (npp->c_stat == NULL)
+ npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_stat[j] = 0;
+ }
+#if 0
+ if (npp->r_prim == NULL)
+ npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_prim[i] = DBL_MAX;
+#endif
+ if (npp->c_value == NULL)
+ npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_value[j] = DBL_MAX;
+ if (npp->sol != GLP_MIP)
+ { if (npp->r_pi == NULL)
+ npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_pi[i] = DBL_MAX;
+#if 0
+ if (npp->c_dual == NULL)
+ npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_dual[j] = DBL_MAX;
+#endif
+ }
+ /* copy solution components from the resultant problem */
+ if (npp->sol == GLP_SOL)
+ { for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ npp->r_stat[k] = (char)row->stat;
+ /*npp->r_prim[k] = row->prim;*/
+ npp->r_pi[k] = dir * row->dual;
+ }
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_stat[k] = (char)col->stat;
+ npp->c_value[k] = col->prim;
+ /*npp->c_dual[k] = dir * col->dual;*/
+ }
+ }
+ else if (npp->sol == GLP_IPT)
+ { for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ /*npp->r_prim[k] = row->pval;*/
+ npp->r_pi[k] = dir * row->dval;
+ }
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_value[k] = col->pval;
+ /*npp->c_dual[k] = dir * col->dval;*/
+ }
+ }
+ else if (npp->sol == GLP_MIP)
+ {
+#if 0
+ for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ /*npp->r_prim[k] = row->mipx;*/
+ }
+#endif
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_value[k] = col->mipx;
+ }
+ }
+ else
+ xassert(npp != npp);
+ /* perform postprocessing to construct solution to the original
+ problem */
+ for (tse = npp->top; tse != NULL; tse = tse->link)
+ { xassert(tse->func != NULL);
+ xassert(tse->func(npp, tse->info) == 0);
+ }
+ return;
+}
+
+void npp_unload_sol(NPP *npp, glp_prob *orig)
+{ /* store solution to the original problem */
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j;
+ double dir;
+ xassert(npp->orig_dir == orig->dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ xassert(npp->orig_m == orig->m);
+ xassert(npp->orig_n == orig->n);
+ xassert(npp->orig_nnz == orig->nnz);
+ if (npp->sol == GLP_SOL)
+ { /* store basic solution */
+ orig->valid = 0;
+ orig->pbs_stat = npp->p_stat;
+ orig->dbs_stat = npp->d_stat;
+ orig->obj_val = orig->c0;
+ orig->some = 0;
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ row->stat = npp->r_stat[i];
+ if (!npp->scaling)
+ { /*row->prim = npp->r_prim[i];*/
+ row->dual = dir * npp->r_pi[i];
+ }
+ else
+ { /*row->prim = npp->r_prim[i] / row->rii;*/
+ row->dual = dir * npp->r_pi[i] * row->rii;
+ }
+ if (row->stat == GLP_BS)
+ row->dual = 0.0;
+ else if (row->stat == GLP_NL)
+ { xassert(row->type == GLP_LO || row->type == GLP_DB);
+ row->prim = row->lb;
+ }
+ else if (row->stat == GLP_NU)
+ { xassert(row->type == GLP_UP || row->type == GLP_DB);
+ row->prim = row->ub;
+ }
+ else if (row->stat == GLP_NF)
+ { xassert(row->type == GLP_FR);
+ row->prim = 0.0;
+ }
+ else if (row->stat == GLP_NS)
+ { xassert(row->type == GLP_FX);
+ row->prim = row->lb;
+ }
+ else
+ xassert(row != row);
+ }
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ col->stat = npp->c_stat[j];
+ if (!npp->scaling)
+ { col->prim = npp->c_value[j];
+ /*col->dual = dir * npp->c_dual[j];*/
+ }
+ else
+ { col->prim = npp->c_value[j] * col->sjj;
+ /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
+ }
+ if (col->stat == GLP_BS)
+ col->dual = 0.0;
+#if 1
+ else if (col->stat == GLP_NL)
+ { xassert(col->type == GLP_LO || col->type == GLP_DB);
+ col->prim = col->lb;
+ }
+ else if (col->stat == GLP_NU)
+ { xassert(col->type == GLP_UP || col->type == GLP_DB);
+ col->prim = col->ub;
+ }
+ else if (col->stat == GLP_NF)
+ { xassert(col->type == GLP_FR);
+ col->prim = 0.0;
+ }
+ else if (col->stat == GLP_NS)
+ { xassert(col->type == GLP_FX);
+ col->prim = col->lb;
+ }
+ else
+ xassert(col != col);
+#endif
+ orig->obj_val += col->coef * col->prim;
+ }
+#if 1
+ /* compute primal values of inactive rows */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ if (row->stat == GLP_BS)
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->prim;
+ row->prim = temp;
+ }
+ }
+ /* compute reduced costs of active columns */
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ if (col->stat != GLP_BS)
+ { GLPAIJ *aij;
+ double temp;
+ temp = col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ temp -= aij->val * aij->row->dual;
+ col->dual = temp;
+ }
+ }
+#endif
+ }
+ else if (npp->sol == GLP_IPT)
+ { /* store interior-point solution */
+ orig->ipt_stat = npp->t_stat;
+ orig->ipt_obj = orig->c0;
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ if (!npp->scaling)
+ { /*row->pval = npp->r_prim[i];*/
+ row->dval = dir * npp->r_pi[i];
+ }
+ else
+ { /*row->pval = npp->r_prim[i] / row->rii;*/
+ row->dval = dir * npp->r_pi[i] * row->rii;
+ }
+ }
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ if (!npp->scaling)
+ { col->pval = npp->c_value[j];
+ /*col->dval = dir * npp->c_dual[j];*/
+ }
+ else
+ { col->pval = npp->c_value[j] * col->sjj;
+ /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
+ }
+ orig->ipt_obj += col->coef * col->pval;
+ }
+#if 1
+ /* compute row primal values */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->pval;
+ row->pval = temp;
+ }
+ }
+ /* compute column dual values */
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ { GLPAIJ *aij;
+ double temp;
+ temp = col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ temp -= aij->val * aij->row->dval;
+ col->dval = temp;
+ }
+ }
+#endif
+ }
+ else if (npp->sol == GLP_MIP)
+ { /* store MIP solution */
+ xassert(!npp->scaling);
+ orig->mip_stat = npp->i_stat;
+ orig->mip_obj = orig->c0;
+#if 0
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ /*row->mipx = npp->r_prim[i];*/
+ }
+#endif
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ col->mipx = npp->c_value[j];
+ if (col->kind == GLP_IV)
+ xassert(col->mipx == floor(col->mipx));
+ orig->mip_obj += col->coef * col->mipx;
+ }
+#if 1
+ /* compute row primal values */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->mipx;
+ row->mipx = temp;
+ }
+ }
+#endif
+ }
+ else
+ xassert(npp != npp);
+ return;
+}
+
+void npp_delete_wksp(NPP *npp)
+{ /* delete LP/MIP preprocessor workspace */
+ if (npp->pool != NULL)
+ dmp_delete_pool(npp->pool);
+ if (npp->stack != NULL)
+ dmp_delete_pool(npp->stack);
+ if (npp->row_ref != NULL)
+ xfree(npp->row_ref);
+ if (npp->col_ref != NULL)
+ xfree(npp->col_ref);
+ if (npp->r_stat != NULL)
+ xfree(npp->r_stat);
+#if 0
+ if (npp->r_prim != NULL)
+ xfree(npp->r_prim);
+#endif
+ if (npp->r_pi != NULL)
+ xfree(npp->r_pi);
+ if (npp->c_stat != NULL)
+ xfree(npp->c_stat);
+ if (npp->c_value != NULL)
+ xfree(npp->c_value);
+#if 0
+ if (npp->c_dual != NULL)
+ xfree(npp->c_dual);
+#endif
+ xfree(npp);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp2.c b/test/monniaux/glpk-4.65/src/npp/npp2.c
new file mode 100644
index 00000000..4efcf1d1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp2.c
@@ -0,0 +1,1433 @@
+/* npp2.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_free_row - process free (unbounded) row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_free_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_free_row processes row p, which is free (i.e. has
+* no finite bounds):
+*
+* -inf < sum a[p,j] x[j] < +inf. (1)
+* j
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) cannot be active, so it is redundant and can be
+* removed from the original problem.
+*
+* Removing row p leads to removing a column of multiplier pi[p] for
+* this row in the dual system. Since row p has no bounds, pi[p] = 0,
+* so removing the column does not affect the dual solution.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In solution to the original problem row p is inactive constraint,
+* so it is assigned status GLP_BS, and multiplier pi[p] is assigned
+* zero value.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* In solution to the original problem row p is inactive constraint,
+* so its multiplier pi[p] is assigned zero value.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct free_row
+{ /* free (unbounded) row */
+ int p;
+ /* row reference number */
+};
+
+static int rcv_free_row(NPP *npp, void *info);
+
+void npp_free_row(NPP *npp, NPPROW *p)
+{ /* process free (unbounded) row */
+ struct free_row *info;
+ /* the row must be free */
+ xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_free_row, sizeof(struct free_row));
+ info->p = p->i;
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return;
+}
+
+static int rcv_free_row(NPP *npp, void *_info)
+{ /* recover free (unbounded) row */
+ struct free_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->r_stat[info->p] = GLP_BS;
+ if (npp->sol != GLP_MIP)
+ npp->r_pi[info->p] = 0.0;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_geq_row - process row of 'not less than' type
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_geq_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_geq_row processes row p, which is 'not less than'
+* inequality constraint:
+*
+* L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
+* j
+*
+* where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) can be replaced by equality constraint:
+*
+* sum a[p,j] x[j] - s = L[p], (2)
+* j
+*
+* where
+*
+* 0 <= s (<= U[p] - L[p]) (3)
+*
+* is a non-negative surplus variable.
+*
+* Since in the primal system there appears column s having the only
+* non-zero coefficient in row p, in the dual system there appears a
+* new row:
+*
+* (-1) pi[p] + lambda = 0, (4)
+*
+* where (-1) is coefficient of column s in row p, pi[p] is multiplier
+* of row p, lambda is multiplier of column q, 0 is coefficient of
+* column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and status of column q in solution to the transformed
+* problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+--------------------+------------------+
+* | Status of row p | Status of column s | Status of row p |
+* +-----------------+--------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_BS | GLP_NU | GLP_BS |
+* | GLP_NS | GLP_BS | GLP_BS |
+* | GLP_NS | GLP_NL | GLP_NL |
+* | GLP_NS | GLP_NU | GLP_NU |
+* +-----------------+--------------------+------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* 1. In solution to the transformed problem row p and column q cannot
+* be basic at the same time; otherwise the basis matrix would have
+* two linear dependent columns: unity column of auxiliary variable
+* of row p and unity column of variable s.
+*
+* 2. Though in the transformed problem row p is equality constraint,
+* it may be basic due to primal degenerate solution.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct ineq_row
+{ /* inequality constraint row */
+ int p;
+ /* row reference number */
+ int s;
+ /* column reference number for slack/surplus variable */
+};
+
+static int rcv_geq_row(NPP *npp, void *info);
+
+void npp_geq_row(NPP *npp, NPPROW *p)
+{ /* process row of 'not less than' type */
+ struct ineq_row *info;
+ NPPCOL *s;
+ /* the row must have lower bound */
+ xassert(p->lb != -DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* create column for surplus variable */
+ s = npp_add_col(npp);
+ s->lb = 0.0;
+ s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+ /* and add it to the transformed problem */
+ npp_add_aij(npp, p, s, -1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_geq_row, sizeof(struct ineq_row));
+ info->p = p->i;
+ info->s = s->j;
+ /* replace the row by equality constraint */
+ p->ub = p->lb;
+ return;
+}
+
+static int rcv_geq_row(NPP *npp, void *_info)
+{ /* recover row of 'not less than' type */
+ struct ineq_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL ||
+ npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->r_stat[info->p] = GLP_NL;
+ else if (npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_NU;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_leq_row - process row of 'not greater than' type
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_leq_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_leq_row processes row p, which is 'not greater than'
+* inequality constraint:
+*
+* (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) can be replaced by equality constraint:
+*
+* sum a[p,j] x[j] + s = L[p], (2)
+* j
+*
+* where
+*
+* 0 <= s (<= U[p] - L[p]) (3)
+*
+* is a non-negative slack variable.
+*
+* Since in the primal system there appears column s having the only
+* non-zero coefficient in row p, in the dual system there appears a
+* new row:
+*
+* (+1) pi[p] + lambda = 0, (4)
+*
+* where (+1) is coefficient of column s in row p, pi[p] is multiplier
+* of row p, lambda is multiplier of column q, 0 is coefficient of
+* column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and status of column q in solution to the transformed
+* problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+--------------------+------------------+
+* | Status of row p | Status of column s | Status of row p |
+* +-----------------+--------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_BS | GLP_NU | GLP_BS |
+* | GLP_NS | GLP_BS | GLP_BS |
+* | GLP_NS | GLP_NL | GLP_NU |
+* | GLP_NS | GLP_NU | GLP_NL |
+* +-----------------+--------------------+------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* 1. In solution to the transformed problem row p and column q cannot
+* be basic at the same time; otherwise the basis matrix would have
+* two linear dependent columns: unity column of auxiliary variable
+* of row p and unity column of variable s.
+*
+* 2. Though in the transformed problem row p is equality constraint,
+* it may be basic due to primal degeneracy.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+static int rcv_leq_row(NPP *npp, void *info);
+
+void npp_leq_row(NPP *npp, NPPROW *p)
+{ /* process row of 'not greater than' type */
+ struct ineq_row *info;
+ NPPCOL *s;
+ /* the row must have upper bound */
+ xassert(p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* create column for slack variable */
+ s = npp_add_col(npp);
+ s->lb = 0.0;
+ s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+ /* and add it to the transformed problem */
+ npp_add_aij(npp, p, s, +1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_leq_row, sizeof(struct ineq_row));
+ info->p = p->i;
+ info->s = s->j;
+ /* replace the row by equality constraint */
+ p->lb = p->ub;
+ return;
+}
+
+static int rcv_leq_row(NPP *npp, void *_info)
+{ /* recover row of 'not greater than' type */
+ struct ineq_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL ||
+ npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->r_stat[info->p] = GLP_NU;
+ else if (npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_free_col - process free (unbounded) column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_free_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_free_col processes column q, which is free (i.e. has
+* no finite bounds):
+*
+* -oo < x[q] < +oo. (1)
+*
+* PROBLEM TRANSFORMATION
+*
+* Free (unbounded) variable can be replaced by the difference of two
+* non-negative variables:
+*
+* x[q] = s' - s'', s', s'' >= 0. (2)
+*
+* Assuming that in the transformed problem x[q] becomes s',
+* transformation (2) causes new column s'' to appear, which differs
+* from column s' only in the sign of coefficients in constraint and
+* objective rows. Thus, if in the dual system the following row
+* corresponds to column s':
+*
+* sum a[i,q] pi[i] + lambda' = c[q], (3)
+* i
+*
+* the row which corresponds to column s'' is the following:
+*
+* sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
+* i
+*
+* Then from (3) and (4) it follows that:
+*
+* lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
+*
+* where lambda' and lambda'' are multipliers for columns s' and s'',
+* resp.
+*
+* RECOVERING BASIC SOLUTION
+*
+* With respect to (5) status of column q in solution to the original
+* problem is determined by statuses of columns s' and s'' in solution
+* to the transformed problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +------------------+-------------------+------------------+
+* | Status of col s' | Status of col s'' | Status of col q |
+* +------------------+-------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_NL | GLP_BS | GLP_BS |
+* | GLP_NL | GLP_NL | GLP_NF |
+* +------------------+-------------------+------------------+
+*
+* Value of column q is computed with formula (2).
+*
+* 1. In solution to the transformed problem columns s' and s'' cannot
+* be basic at the same time, because they differ only in the sign,
+* hence, are linear dependent.
+*
+* 2. Though column q is free, it can be non-basic due to dual
+* degeneracy.
+*
+* 3. If column q is integral, columns s' and s'' are also integral.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+struct free_col
+{ /* free (unbounded) column */
+ int q;
+ /* column reference number for variables x[q] and s' */
+ int s;
+ /* column reference number for variable s'' */
+};
+
+static int rcv_free_col(NPP *npp, void *info);
+
+void npp_free_col(NPP *npp, NPPCOL *q)
+{ /* process free (unbounded) column */
+ struct free_col *info;
+ NPPCOL *s;
+ NPPAIJ *aij;
+ /* the column must be free */
+ xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
+ /* variable x[q] becomes s' */
+ q->lb = 0.0, q->ub = +DBL_MAX;
+ /* create variable s'' */
+ s = npp_add_col(npp);
+ s->is_int = q->is_int;
+ s->lb = 0.0, s->ub = +DBL_MAX;
+ /* duplicate objective coefficient */
+ s->coef = -q->coef;
+ /* duplicate column of the constraint matrix */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ npp_add_aij(npp, aij->row, s, -aij->val);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_free_col, sizeof(struct free_col));
+ info->q = q->j;
+ info->s = s->j;
+ return;
+}
+
+static int rcv_free_col(NPP *npp, void *_info)
+{ /* recover free (unbounded) column */
+ struct free_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_BS;
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NF;
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] -= npp->c_value[info->s];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_lbnd_col - process column with (non-zero) lower bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_lbnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_lbnd_col processes column q, which has (non-zero)
+* lower bound:
+*
+* l[q] <= x[q] (<= u[q]), (1)
+*
+* where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Column q can be replaced as follows:
+*
+* x[q] = l[q] + s, (2)
+*
+* where
+*
+* 0 <= s (<= u[q] - l[q]) (3)
+*
+* is a non-negative variable.
+*
+* Substituting x[q] from (2) into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] s + c~0,
+*
+* where
+*
+* c~0 = c0 + c[q] l[q] (4)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* Transformation (2) does not affect the dual system.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is the same
+* as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
+* Value of column q is computed with formula (2).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+struct bnd_col
+{ /* bounded column */
+ int q;
+ /* column reference number for variables x[q] and s */
+ double bnd;
+ /* lower/upper bound l[q] or u[q] */
+};
+
+static int rcv_lbnd_col(NPP *npp, void *info);
+
+void npp_lbnd_col(NPP *npp, NPPCOL *q)
+{ /* process column with (non-zero) lower bound */
+ struct bnd_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must have non-zero lower bound */
+ xassert(q->lb != 0.0);
+ xassert(q->lb != -DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_lbnd_col, sizeof(struct bnd_col));
+ info->q = q->j;
+ info->bnd = q->lb;
+ /* substitute x[q] into objective row */
+ npp->c0 += q->coef * q->lb;
+ /* substitute x[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->lb;
+ }
+ }
+ /* column x[q] becomes column s */
+ if (q->ub != +DBL_MAX)
+ q->ub -= q->lb;
+ q->lb = 0.0;
+ return;
+}
+
+static int rcv_lbnd_col(NPP *npp, void *_info)
+{ /* recover column with (non-zero) lower bound */
+ struct bnd_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS ||
+ npp->c_stat[info->q] == GLP_NL ||
+ npp->c_stat[info->q] == GLP_NU)
+ npp->c_stat[info->q] = npp->c_stat[info->q];
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_ubnd_col - process column with upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_ubnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_ubnd_col processes column q, which has upper bound:
+*
+* (l[q] <=) x[q] <= u[q], (1)
+*
+* where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Column q can be replaced as follows:
+*
+* x[q] = u[q] - s, (2)
+*
+* where
+*
+* 0 <= s (<= u[q] - l[q]) (3)
+*
+* is a non-negative variable.
+*
+* Substituting x[q] from (2) into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
+* j!=q
+*
+* = sum c[j] x[j] - c[q] s + c~0,
+*
+* where
+*
+* c~0 = c0 + c[q] u[q] (4)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* Note that in the transformed problem coefficients c[q] and a[i,q]
+* change their sign. Thus, the row of the dual system corresponding to
+* column q:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] (6)
+* i
+*
+* in the transformed problem becomes the following:
+*
+* sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
+* i
+*
+* Therefore:
+*
+* lambda[q] = - lambda[s], (8)
+*
+* where lambda[q] is multiplier for column q, lambda[s] is multiplier
+* for column s.
+*
+* RECOVERING BASIC SOLUTION
+*
+* With respect to (8) status of column q in solution to the original
+* problem is determined by status of column s in solution to the
+* transformed problem as follows:
+*
+* +-----------------------+--------------------+
+* | Status of column s | Status of column q |
+* | (transformed problem) | (original problem) |
+* +-----------------------+--------------------+
+* | GLP_BS | GLP_BS |
+* | GLP_NL | GLP_NU |
+* | GLP_NU | GLP_NL |
+* +-----------------------+--------------------+
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+static int rcv_ubnd_col(NPP *npp, void *info);
+
+void npp_ubnd_col(NPP *npp, NPPCOL *q)
+{ /* process column with upper bound */
+ struct bnd_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must have upper bound */
+ xassert(q->ub != +DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_ubnd_col, sizeof(struct bnd_col));
+ info->q = q->j;
+ info->bnd = q->ub;
+ /* substitute x[q] into objective row */
+ npp->c0 += q->coef * q->ub;
+ q->coef = -q->coef;
+ /* substitute x[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->ub);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->ub;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->ub;
+ }
+ aij->val = -aij->val;
+ }
+ /* column x[q] becomes column s */
+ if (q->lb != -DBL_MAX)
+ q->ub -= q->lb;
+ else
+ q->ub = +DBL_MAX;
+ q->lb = 0.0;
+ return;
+}
+
+static int rcv_ubnd_col(NPP *npp, void *_info)
+{ /* recover column with upper bound */
+ struct bnd_col *info = _info;
+ if (npp->sol == GLP_BS)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->q] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NU;
+ else if (npp->c_stat[info->q] == GLP_NU)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_dbnd_col - process non-negative column with upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_dbnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_dbnd_col processes column q, which is non-negative
+* and has upper bound:
+*
+* 0 <= x[q] <= u[q], (1)
+*
+* where u[q] > 0.
+*
+* PROBLEM TRANSFORMATION
+*
+* Upper bound of column q can be replaced by the following equality
+* constraint:
+*
+* x[q] + s = u[q], (2)
+*
+* where s >= 0 is a non-negative complement variable.
+*
+* Since in the primal system along with new row (2) there appears a
+* new column s having the only non-zero coefficient in this row, in
+* the dual system there appears a new row:
+*
+* (+1)pi + lambda[s] = 0, (3)
+*
+* where (+1) is coefficient at column s in row (2), pi is multiplier
+* for row (2), lambda[s] is multiplier for column s, 0 is coefficient
+* at column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is determined
+* by its status and status of column s in solution to the transformed
+* problem as follows:
+*
+* +-----------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+-----------------+------------------+
+* | Status of col q | Status of col s | Status of col q |
+* +-----------------+-----------------+------------------+
+* | GLP_BS | GLP_BS | GLP_BS |
+* | GLP_BS | GLP_NL | GLP_NU |
+* | GLP_NL | GLP_BS | GLP_NL |
+* | GLP_NL | GLP_NL | GLP_NL (*) |
+* +-----------------+-----------------+------------------+
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* 1. Formally, in solution to the transformed problem columns q and s
+* cannot be non-basic at the same time, since the constraint (2)
+* would be violated. However, if u[q] is close to zero, violation
+* may be less than a working precision even if both columns q and s
+* are non-basic. In this degenerate case row (2) can be only basic,
+* i.e. non-active constraint (otherwise corresponding row of the
+* basis matrix would be zero). This allows to pivot out auxiliary
+* variable and pivot in column s, in which case the row becomes
+* active while column s becomes basic.
+*
+* 2. If column q is integral, column s is also integral.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem. */
+
+struct dbnd_col
+{ /* double-bounded column */
+ int q;
+ /* column reference number for variable x[q] */
+ int s;
+ /* column reference number for complement variable s */
+};
+
+static int rcv_dbnd_col(NPP *npp, void *info);
+
+void npp_dbnd_col(NPP *npp, NPPCOL *q)
+{ /* process non-negative column with upper bound */
+ struct dbnd_col *info;
+ NPPROW *p;
+ NPPCOL *s;
+ /* the column must be non-negative with upper bound */
+ xassert(q->lb == 0.0);
+ xassert(q->ub > 0.0);
+ xassert(q->ub != +DBL_MAX);
+ /* create variable s */
+ s = npp_add_col(npp);
+ s->is_int = q->is_int;
+ s->lb = 0.0, s->ub = +DBL_MAX;
+ /* create equality constraint (2) */
+ p = npp_add_row(npp);
+ p->lb = p->ub = q->ub;
+ npp_add_aij(npp, p, q, +1.0);
+ npp_add_aij(npp, p, s, +1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_dbnd_col, sizeof(struct dbnd_col));
+ info->q = q->j;
+ info->s = s->j;
+ /* remove upper bound of x[q] */
+ q->ub = +DBL_MAX;
+ return;
+}
+
+static int rcv_dbnd_col(NPP *npp, void *_info)
+{ /* recover non-negative column with upper bound */
+ struct dbnd_col *info = _info;
+ if (npp->sol == GLP_BS)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NU;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+ { if (npp->c_stat[info->s] == GLP_BS ||
+ npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_fixed_col - process fixed column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_fixed_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_fixed_col processes column q, which is fixed:
+*
+* x[q] = s[q], (1)
+*
+* where s[q] is a fixed column value.
+*
+* PROBLEM TRANSFORMATION
+*
+* The value of a fixed column can be substituted into the objective
+* and constraint rows that allows removing the column from the problem.
+*
+* Substituting x[q] = s[q] into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] s[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c~0,
+* j!=q
+*
+* where
+*
+* c~0 = c0 + c[q] s[q] (2)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] = s[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Column q is assigned status GLP_NS and its value is assigned s[q].
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is assigned s[q].
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is assigned s[q]. */
+
+struct fixed_col
+{ /* fixed column */
+ int q;
+ /* column reference number for variable x[q] */
+ double s;
+ /* value, at which x[q] is fixed */
+};
+
+static int rcv_fixed_col(NPP *npp, void *info);
+
+void npp_fixed_col(NPP *npp, NPPCOL *q)
+{ /* process fixed column */
+ struct fixed_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must be fixed */
+ xassert(q->lb == q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_fixed_col, sizeof(struct fixed_col));
+ info->q = q->j;
+ info->s = q->lb;
+ /* substitute x[q] = s[q] into objective row */
+ npp->c0 += q->coef * q->lb;
+ /* substitute x[q] = s[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->lb;
+ }
+ }
+ /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return;
+}
+
+static int rcv_fixed_col(NPP *npp, void *_info)
+{ /* recover fixed column */
+ struct fixed_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->c_stat[info->q] = GLP_NS;
+ npp->c_value[info->q] = info->s;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_make_equality - process row with almost identical bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_make_equality(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_make_equality processes row p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
+* constraint.
+*
+* RETURNS
+*
+* 0 - row bounds have not been changed;
+*
+* 1 - row has been replaced by equality constraint.
+*
+* PROBLEM TRANSFORMATION
+*
+* If bounds of row (1) are very close to each other:
+*
+* U[p] - L[p] <= eps, (2)
+*
+* where eps is an absolute tolerance for row value, the row can be
+* replaced by the following almost equivalent equiality constraint:
+*
+* sum a[p,j] x[j] = b, (3)
+* j
+*
+* where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
+* to be very close to its nearest integer:
+*
+* |b - floor(b + 0.5)| <= eps, (4)
+*
+* it is reasonable to use this nearest integer as the right-hand side.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and the sign of its multiplier pi[p] in solution to
+* the transformed problem as follows:
+*
+* +-----------------------+---------+--------------------+
+* | Status of row p | Sign of | Status of row p |
+* | (transformed problem) | pi[p] | (original problem) |
+* +-----------------------+---------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NS | + | GLP_NL |
+* | GLP_NS | - | GLP_NU |
+* +-----------------------+---------+--------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING INTERIOR POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct make_equality
+{ /* row with almost identical bounds */
+ int p;
+ /* row reference number */
+};
+
+static int rcv_make_equality(NPP *npp, void *info);
+
+int npp_make_equality(NPP *npp, NPPROW *p)
+{ /* process row with almost identical bounds */
+ struct make_equality *info;
+ double b, eps, nint;
+ /* the row must be double-sided inequality */
+ xassert(p->lb != -DBL_MAX);
+ xassert(p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* check row bounds */
+ eps = 1e-9 + 1e-12 * fabs(p->lb);
+ if (p->ub - p->lb > eps) return 0;
+ /* row bounds are very close to each other */
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_make_equality, sizeof(struct make_equality));
+ info->p = p->i;
+ /* compute right-hand side */
+ b = 0.5 * (p->ub + p->lb);
+ nint = floor(b + 0.5);
+ if (fabs(b - nint) <= eps) b = nint;
+ /* replace row p by almost equivalent equality constraint */
+ p->lb = p->ub = b;
+ return 1;
+}
+
+int rcv_make_equality(NPP *npp, void *_info)
+{ /* recover row with almost identical bounds */
+ struct make_equality *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->r_pi[info->p] >= 0.0)
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_make_fixed - process column with almost identical bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_make_fixed(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_make_fixed processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
+* bounds.
+*
+* RETURNS
+*
+* 0 - column bounds have not been changed;
+*
+* 1 - column has been fixed.
+*
+* PROBLEM TRANSFORMATION
+*
+* If bounds of column (1) are very close to each other:
+*
+* u[q] - l[q] <= eps, (2)
+*
+* where eps is an absolute tolerance for column value, the column can
+* be fixed:
+*
+* x[q] = s[q], (3)
+*
+* where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
+* happens to be very close to its nearest integer:
+*
+* |s[q] - floor(s[q] + 0.5)| <= eps, (4)
+*
+* it is reasonable to use this nearest integer as the fixed value.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In the dual system of the original (as well as transformed) problem
+* column q corresponds to the following row:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
+* i
+*
+* Since multipliers pi[i] are known for all rows from solution to the
+* transformed problem, formula (5) allows computing value of multiplier
+* (reduced cost) for column q:
+*
+* lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
+* i
+*
+* Status of column q in solution to the original problem is determined
+* by its status and the sign of its multiplier lambda[q] in solution to
+* the transformed problem as follows:
+*
+* +-----------------------+-----------+--------------------+
+* | Status of column q | Sign of | Status of column q |
+* | (transformed problem) | lambda[q] | (original problem) |
+* +-----------------------+-----------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NS | + | GLP_NL |
+* | GLP_NS | - | GLP_NU |
+* +-----------------------+-----------+--------------------+
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING INTERIOR POINT SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct make_fixed
+{ /* column with almost identical bounds */
+ int q;
+ /* column reference number */
+ double c;
+ /* objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q] */
+};
+
+static int rcv_make_fixed(NPP *npp, void *info);
+
+int npp_make_fixed(NPP *npp, NPPCOL *q)
+{ /* process column with almost identical bounds */
+ struct make_fixed *info;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ double s, eps, nint;
+ /* the column must be double-bounded */
+ xassert(q->lb != -DBL_MAX);
+ xassert(q->ub != +DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* check column bounds */
+ eps = 1e-9 + 1e-12 * fabs(q->lb);
+ if (q->ub - q->lb > eps) return 0;
+ /* column bounds are very close to each other */
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_make_fixed, sizeof(struct make_fixed));
+ info->q = q->j;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q] (needed for basic solution
+ only) */
+ if (npp->sol == GLP_SOL)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* compute column fixed value */
+ s = 0.5 * (q->ub + q->lb);
+ nint = floor(s + 0.5);
+ if (fabs(s - nint) <= eps) s = nint;
+ /* make column q fixed */
+ q->lb = q->ub = s;
+ return 1;
+}
+
+static int rcv_make_fixed(NPP *npp, void *_info)
+{ /* recover column with almost identical bounds */
+ struct make_fixed *info = _info;
+ NPPLFE *lfe;
+ double lambda;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->q] == GLP_NS)
+ { /* compute multiplier for column q with formula (6) */
+ lambda = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ lambda -= lfe->val * npp->r_pi[lfe->ref];
+ /* assign status to non-basic column */
+ if (lambda >= 0.0)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ npp->c_stat[info->q] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp3.c b/test/monniaux/glpk-4.65/src/npp/npp3.c
new file mode 100644
index 00000000..883af127
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp3.c
@@ -0,0 +1,2861 @@
+/* npp3.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_empty_row - process empty row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_empty_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_empty_row processes row p, which is empty, i.e.
+* coefficients at all columns in this row are zero:
+*
+* L[p] <= sum 0 x[j] <= U[p], (1)
+*
+* where L[p] <= U[p].
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no primal feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* If the following conditions hold:
+*
+* L[p] <= +eps, U[p] >= -eps, (2)
+*
+* where eps is an absolute tolerance for row value, the row p is
+* redundant. In this case it can be replaced by equivalent redundant
+* row, which is free (unbounded), and then removed from the problem.
+* Otherwise, the row p is infeasible and, thus, the problem has no
+* primal feasible solution.
+*
+* RECOVERING BASIC SOLUTION
+*
+* See the routine npp_free_row.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* See the routine npp_free_row.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+int npp_empty_row(NPP *npp, NPPROW *p)
+{ /* process empty row */
+ double eps = 1e-3;
+ /* the row must be empty */
+ xassert(p->ptr == NULL);
+ /* check primal feasibility */
+ if (p->lb > +eps || p->ub < -eps)
+ return 1;
+ /* replace the row by equivalent free (unbounded) row */
+ p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ /* and process it */
+ npp_free_row(npp, p);
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_empty_col - process empty column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_empty_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_empty_col processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] <= u[q], which is empty, i.e. has zero coefficients in
+* all constraint rows.
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no dual feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* The row of the dual system corresponding to the empty column is the
+* following:
+*
+* sum 0 pi[i] + lambda[q] = c[q], (2)
+* i
+*
+* from which it follows that:
+*
+* lambda[q] = c[q]. (3)
+*
+* If the following condition holds:
+*
+* c[q] < - eps, (4)
+*
+* where eps is an absolute tolerance for column multiplier, the lower
+* column bound l[q] must be active to provide dual feasibility (note
+* that being preprocessed the problem is always minimization). In this
+* case the column can be fixed on its lower bound and removed from the
+* problem (if the column is integral, its bounds are also assumed to
+* be integral). And if the column has no lower bound (l[q] = -oo), the
+* problem has no dual feasible solution.
+*
+* If the following condition holds:
+*
+* c[q] > + eps, (5)
+*
+* the upper column bound u[q] must be active to provide dual
+* feasibility. In this case the column can be fixed on its upper bound
+* and removed from the problem. And if the column has no upper bound
+* (u[q] = +oo), the problem has no dual feasible solution.
+*
+* Finally, if the following condition holds:
+*
+* - eps <= c[q] <= +eps, (6)
+*
+* dual feasibility does not depend on a particular value of column q.
+* In this case the column can be fixed either on its lower bound (if
+* l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
+* column is unbounded) and then removed from the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* See the routine npp_fixed_col. Having been recovered the column
+* is assigned status GLP_NS. However, if actually it is not fixed
+* (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
+* GLP_NF depending on which bound it was fixed on transformation stage.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* See the routine npp_fixed_col.
+*
+* RECOVERING MIP SOLUTION
+*
+* See the routine npp_fixed_col. */
+
+struct empty_col
+{ /* empty column */
+ int q;
+ /* column reference number */
+ char stat;
+ /* status in basic solution */
+};
+
+static int rcv_empty_col(NPP *npp, void *info);
+
+int npp_empty_col(NPP *npp, NPPCOL *q)
+{ /* process empty column */
+ struct empty_col *info;
+ double eps = 1e-3;
+ /* the column must be empty */
+ xassert(q->ptr == NULL);
+ /* check dual feasibility */
+ if (q->coef > +eps && q->lb == -DBL_MAX)
+ return 1;
+ if (q->coef < -eps && q->ub == +DBL_MAX)
+ return 1;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_empty_col, sizeof(struct empty_col));
+ info->q = q->j;
+ /* fix the column */
+ if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
+ { /* free column */
+ info->stat = GLP_NF;
+ q->lb = q->ub = 0.0;
+ }
+ else if (q->ub == +DBL_MAX)
+lo: { /* column with lower bound */
+ info->stat = GLP_NL;
+ q->ub = q->lb;
+ }
+ else if (q->lb == -DBL_MAX)
+up: { /* column with upper bound */
+ info->stat = GLP_NU;
+ q->lb = q->ub;
+ }
+ else if (q->lb != q->ub)
+ { /* double-bounded column */
+ if (q->coef >= +DBL_EPSILON) goto lo;
+ if (q->coef <= -DBL_EPSILON) goto up;
+ if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
+ }
+ else
+ { /* fixed column */
+ info->stat = GLP_NS;
+ }
+ /* process fixed column */
+ npp_fixed_col(npp, q);
+ return 0;
+}
+
+static int rcv_empty_col(NPP *npp, void *_info)
+{ /* recover empty column */
+ struct empty_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->c_stat[info->q] = info->stat;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_value - process implied column value
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_value processes its
+* implied value s[q]. If this implied value satisfies to the current
+* column bounds and integrality condition, the routine fixes column q
+* at the given point. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - column has been fixed;
+*
+* 1 - implied value violates to current column bounds;
+*
+* 2 - implied value violates integrality condition.
+*
+* ALGORITHM
+*
+* Implied column value s[q] satisfies to the current column bounds if
+* the following condition holds:
+*
+* l[q] - eps <= s[q] <= u[q] + eps, (2)
+*
+* where eps is an absolute tolerance for column value. If the column
+* is integral, the following condition also must hold:
+*
+* |s[q] - floor(s[q]+0.5)| <= eps, (3)
+*
+* where floor(s[q]+0.5) is the nearest integer to s[q].
+*
+* If both condition (2) and (3) are satisfied, the column can be fixed
+* at the value s[q], or, if it is integral, at floor(s[q]+0.5).
+* Otherwise, if s[q] violates (2) or (3), the problem has no feasible
+* solution.
+*
+* Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
+* fix the column at its lower or upper bound, resp. rather than at the
+* implied value. */
+
+int npp_implied_value(NPP *npp, NPPCOL *q, double s)
+{ /* process implied column value */
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* check integrality */
+ if (q->is_int)
+ { nint = floor(s + 0.5);
+ if (fabs(s - nint) <= 1e-5)
+ s = nint;
+ else
+ return 2;
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+ if (s < q->lb - eps) return 1;
+ /* if s[q] is close to l[q], fix column at its lower bound
+ rather than at the implied value */
+ if (s < q->lb + 1e-3 * eps)
+ { q->ub = q->lb;
+ return 0;
+ }
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+ if (s > q->ub + eps) return 1;
+ /* if s[q] is close to u[q], fix column at its upper bound
+ rather than at the implied value */
+ if (s > q->ub - 1e-3 * eps)
+ { q->lb = q->ub;
+ return 0;
+ }
+ }
+ /* fix column at the implied value */
+ q->lb = q->ub = s;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_eq_singlet - process row singleton (equality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_eq_singlet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_eq_singlet processes row p, which is equiality
+* constraint having the only non-zero coefficient:
+*
+* a[p,q] x[q] = b. (1)
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no primal feasible solution;
+*
+* 2 - problem has no integer feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* The equality constraint defines implied value of column q:
+*
+* x[q] = s[q] = b / a[p,q]. (2)
+*
+* If the implied value s[q] satisfies to the column bounds (see the
+* routine npp_implied_value), the column can be fixed at s[q] and
+* removed from the problem. In this case row p becomes redundant, so
+* it can be replaced by equivalent free row and also removed from the
+* problem.
+*
+* Note that the routine removes from the problem only row p. Column q
+* becomes fixed, however, it is kept in the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In solution to the original problem row p is assigned status GLP_NS
+* (active equality constraint), and column q is assigned status GLP_BS
+* (basic column).
+*
+* Multiplier for row p can be computed as follows. In the dual system
+* of the original problem column q corresponds to the following row:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
+* i
+*
+* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
+* i!=p
+*
+* Therefore:
+*
+* 1
+* pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]), (3)
+* a[p,q] i!=q
+*
+* where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
+* i != p are known in solution to the transformed problem.
+*
+* Value of column q in solution to the original problem is assigned
+* its implied value s[q].
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Multiplier for row p is computed with formula (3). Value of column
+* q is assigned its implied value s[q].
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is assigned its implied value s[q]. */
+
+struct eq_singlet
+{ /* row singleton (equality constraint) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double c;
+ /* objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_singlet(NPP *npp, void *info);
+
+int npp_eq_singlet(NPP *npp, NPPROW *p)
+{ /* process row singleton (equality constraint) */
+ struct eq_singlet *info;
+ NPPCOL *q;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ int ret;
+ double s;
+ /* the row must be singleton equality constraint */
+ xassert(p->lb == p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+ /* compute and process implied column value */
+ aij = p->ptr;
+ q = aij->col;
+ s = p->lb / aij->val;
+ ret = npp_implied_value(npp, q, s);
+ xassert(0 <= ret && ret <= 2);
+ if (ret != 0) return ret;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_eq_singlet, sizeof(struct eq_singlet));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = aij->val;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q], i != p (not needed for MIP
+ solution) */
+ if (npp->sol != GLP_MIP)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij->row == p) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return 0;
+}
+
+static int rcv_eq_singlet(NPP *npp, void *_info)
+{ /* recover row singleton (equality constraint) */
+ struct eq_singlet *info = _info;
+ NPPLFE *lfe;
+ double temp;
+ if (npp->sol == GLP_SOL)
+ { /* column q must be already recovered as GLP_NS */
+ if (npp->c_stat[info->q] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ npp->r_stat[info->p] = GLP_NS;
+ npp->c_stat[info->q] = GLP_BS;
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute multiplier for row p with formula (3) */
+ temp = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ temp -= lfe->val * npp->r_pi[lfe->ref];
+ npp->r_pi[info->p] = temp / info->apq;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_lower - process implied column lower bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_lower processes its
+* implied lower bound l'[q]. As the result the current column lower
+* bound may increase. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - current column lower bound has not changed;
+*
+* 1 - current column lower bound has changed, but not significantly;
+*
+* 2 - current column lower bound has significantly changed;
+*
+* 3 - column has been fixed on its upper bound;
+*
+* 4 - implied lower bound violates current column upper bound.
+*
+* ALGORITHM
+*
+* If column q is integral, before processing its implied lower bound
+* should be rounded up:
+*
+* ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
+* l'[q] := < (2)
+* ( ceil(l'[q]), otherwise
+*
+* where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
+* is smallest integer not less than l'[q], and eps is an absolute
+* tolerance for column value.
+*
+* Processing implied column lower bound l'[q] includes the following
+* cases:
+*
+* 1) if l'[q] < l[q] + eps, implied lower bound is redundant;
+*
+* 2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
+* l[q] can be strengthened by replacing it with l'[q]. If in this
+* case new column lower bound becomes close to current column upper
+* bound u[q], the column can be fixed on its upper bound;
+*
+* 3) if l'[q] > u[q] + eps, implied lower bound violates current
+* column upper bound u[q], in which case the problem has no primal
+* feasible solution. */
+
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
+{ /* process implied column lower bound */
+ int ret;
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* implied lower bound must be finite */
+ xassert(l != -DBL_MAX);
+ /* if column is integral, round up l'[q] */
+ if (q->is_int)
+ { nint = floor(l + 0.5);
+ if (fabs(l - nint) <= 1e-5)
+ l = nint;
+ else
+ l = ceil(l);
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
+ if (l < q->lb + eps)
+ { ret = 0; /* redundant */
+ goto done;
+ }
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+ if (l > q->ub + eps)
+ { ret = 4; /* infeasible */
+ goto done;
+ }
+ /* if l'[q] is close to u[q], fix column at its upper bound */
+ if (l > q->ub - 1e-3 * eps)
+ { q->lb = q->ub;
+ ret = 3; /* fixed */
+ goto done;
+ }
+ }
+ /* check if column lower bound changes significantly */
+ if (q->lb == -DBL_MAX)
+ ret = 2; /* significantly */
+ else if (q->is_int && l > q->lb + 0.5)
+ ret = 2; /* significantly */
+ else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
+ ret = 2; /* significantly */
+ else
+ ret = 1; /* not significantly */
+ /* set new column lower bound */
+ q->lb = l;
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_upper - process implied column upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_upper processes its
+* implied upper bound u'[q]. As the result the current column upper
+* bound may decrease. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - current column upper bound has not changed;
+*
+* 1 - current column upper bound has changed, but not significantly;
+*
+* 2 - current column upper bound has significantly changed;
+*
+* 3 - column has been fixed on its lower bound;
+*
+* 4 - implied upper bound violates current column lower bound.
+*
+* ALGORITHM
+*
+* If column q is integral, before processing its implied upper bound
+* should be rounded down:
+*
+* ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
+* u'[q] := < (2)
+* ( floor(l'[q]), otherwise
+*
+* where floor(u'[q]+0.5) is the nearest integer to u'[q],
+* floor(u'[q]) is largest integer not greater than u'[q], and eps is
+* an absolute tolerance for column value.
+*
+* Processing implied column upper bound u'[q] includes the following
+* cases:
+*
+* 1) if u'[q] > u[q] - eps, implied upper bound is redundant;
+*
+* 2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
+* u[q] can be strengthened by replacing it with u'[q]. If in this
+* case new column upper bound becomes close to current column lower
+* bound, the column can be fixed on its lower bound;
+*
+* 3) if u'[q] < l[q] - eps, implied upper bound violates current
+* column lower bound l[q], in which case the problem has no primal
+* feasible solution. */
+
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
+{ int ret;
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* implied upper bound must be finite */
+ xassert(u != +DBL_MAX);
+ /* if column is integral, round down u'[q] */
+ if (q->is_int)
+ { nint = floor(u + 0.5);
+ if (fabs(u - nint) <= 1e-5)
+ u = nint;
+ else
+ u = floor(u);
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
+ if (u > q->ub - eps)
+ { ret = 0; /* redundant */
+ goto done;
+ }
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+ if (u < q->lb - eps)
+ { ret = 4; /* infeasible */
+ goto done;
+ }
+ /* if u'[q] is close to l[q], fix column at its lower bound */
+ if (u < q->lb + 1e-3 * eps)
+ { q->ub = q->lb;
+ ret = 3; /* fixed */
+ goto done;
+ }
+ }
+ /* check if column upper bound changes significantly */
+ if (q->ub == +DBL_MAX)
+ ret = 2; /* significantly */
+ else if (q->is_int && u < q->ub - 0.5)
+ ret = 2; /* significantly */
+ else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
+ ret = 2; /* significantly */
+ else
+ ret = 1; /* not significantly */
+ /* set new column upper bound */
+ q->ub = u;
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_ineq_singlet - process row singleton (inequality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_ineq_singlet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_ineq_singlet processes row p, which is inequality
+* constraint having the only non-zero coefficient:
+*
+* L[p] <= a[p,q] * x[q] <= U[p], (1)
+*
+* where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+* RETURNS
+*
+* 0 - current column bounds have not changed;
+*
+* 1 - current column bounds have changed, but not significantly;
+*
+* 2 - current column bounds have significantly changed;
+*
+* 3 - column has been fixed on its lower or upper bound;
+*
+* 4 - problem has no primal feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* Inequality constraint (1) defines implied bounds of column q:
+*
+* ( L[p] / a[p,q], if a[p,q] > 0
+* l'[q] = < (2)
+* ( U[p] / a[p,q], if a[p,q] < 0
+*
+* ( U[p] / a[p,q], if a[p,q] > 0
+* u'[q] = < (3)
+* ( L[p] / a[p,q], if a[p,q] < 0
+*
+* If these implied bounds do not violate current bounds of column q:
+*
+* l[q] <= x[q] <= u[q], (4)
+*
+* they can be used to strengthen the current column bounds:
+*
+* l[q] := max(l[q], l'[q]), (5)
+*
+* u[q] := min(u[q], u'[q]). (6)
+*
+* (See the routines npp_implied_lower and npp_implied_upper.)
+*
+* Once bounds of row p (1) have been carried over column q, the row
+* becomes redundant, so it can be replaced by equivalent free row and
+* removed from the problem.
+*
+* Note that the routine removes from the problem only row p. Column q,
+* even it has been fixed, is kept in the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Note that the row in the dual system corresponding to column q is
+* the following:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
+* i
+* (7)
+* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
+* i!=p
+*
+* where pi[i] for all i != p are known in solution to the transformed
+* problem. Row p does not exist in the transformed problem, so it has
+* zero multiplier there. This allows computing multiplier for column q
+* in solution to the transformed problem:
+*
+* lambda~[q] = c[q] - sum a[i,q] pi[i]. (8)
+* i!=p
+*
+* Let in solution to the transformed problem column q be non-basic
+* with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
+* bound be implied one l'[q]. From the original problem's standpoint
+* this then means that actually the original column lower bound l[q]
+* is inactive, and active is that row bound L[p] or U[p] that defines
+* the implied bound l'[q] (2). In this case in solution to the
+* original problem column q is assigned status GLP_BS while row p is
+* assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
+* Since now column q is basic, its multiplier lambda[q] is zero. This
+* allows using (7) and (8) to find multiplier for row p in solution to
+* the original problem:
+*
+* 1
+* pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
+* a[p,q] i!=p
+*
+* Now let in solution to the transformed problem column q be non-basic
+* with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
+* bound be implied one u'[q]. As in the previous case this then means
+* that from the original problem's standpoint actually the original
+* column upper bound u[q] is inactive, and active is that row bound
+* L[p] or U[p] that defines the implied bound u'[q] (3). In this case
+* in solution to the original problem column q is assigned status
+* GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
+* (if a[p,q] < 0), and its multiplier is computed with formula (9).
+*
+* Strengthening bounds of column q according to (5) and (6) may make
+* it fixed. Thus, if in solution to the transformed problem column q is
+* non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
+* column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
+* column q has active upper bound (GLP_NU), reducing this case to two
+* previous ones. If, however, lambda~[q] is close to zero or
+* corresponding bound of row p does not exist (this may happen if
+* lambda~[q] has wrong sign due to round-off errors, in which case it
+* is expected to be close to zero, since solution is assumed to be dual
+* feasible), column q can be assigned status GLP_BS (basic), and row p
+* can be made active on its existing bound. In the latter case row
+* multiplier pi[p] computed with formula (9) will be also close to
+* zero, and dual feasibility will be kept.
+*
+* In all other cases, namely, if in solution to the transformed
+* problem column q is basic (GLP_BS), or non-basic with original lower
+* bound l[q] active (GLP_NL), or non-basic with original upper bound
+* u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
+* the original problem status of column q remains unchanged, row p is
+* assigned status GLP_BS, and its multiplier pi[p] is assigned zero
+* value.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* First, value of multiplier for column q in solution to the original
+* problem is computed with formula (8). If lambda~[q] > 0 and column q
+* has implied lower bound, or if lambda~[q] < 0 and column q has
+* implied upper bound, this means that from the original problem's
+* standpoint actually row p has corresponding active bound, in which
+* case its multiplier pi[p] is computed with formula (9). In other
+* cases, when the sign of lambda~[q] corresponds to original bound of
+* column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
+* assigned zero value.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct ineq_singlet
+{ /* row singleton (inequality constraint) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double c;
+ /* objective coefficient at x[q] */
+ double lb;
+ /* row lower bound */
+ double ub;
+ /* row upper bound */
+ char lb_changed;
+ /* this flag is set if column lower bound was changed */
+ char ub_changed;
+ /* this flag is set if column upper bound was changed */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_ineq_singlet(NPP *npp, void *info);
+
+int npp_ineq_singlet(NPP *npp, NPPROW *p)
+{ /* process row singleton (inequality constraint) */
+ struct ineq_singlet *info;
+ NPPCOL *q;
+ NPPAIJ *apq, *aij;
+ NPPLFE *lfe;
+ int lb_changed, ub_changed;
+ double ll, uu;
+ /* the row must be singleton inequality constraint */
+ xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+ /* compute implied column bounds */
+ apq = p->ptr;
+ q = apq->col;
+ xassert(q->lb < q->ub);
+ if (apq->val > 0.0)
+ { ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
+ uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
+ }
+ else
+ { ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
+ uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
+ }
+ /* process implied column lower bound */
+ if (ll == -DBL_MAX)
+ lb_changed = 0;
+ else
+ { lb_changed = npp_implied_lower(npp, q, ll);
+ xassert(0 <= lb_changed && lb_changed <= 4);
+ if (lb_changed == 4) return 4; /* infeasible */
+ }
+ /* process implied column upper bound */
+ if (uu == +DBL_MAX)
+ ub_changed = 0;
+ else if (lb_changed == 3)
+ { /* column was fixed on its upper bound due to l'[q] = u[q] */
+ /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
+ ub_changed = 0;
+ }
+ else
+ { ub_changed = npp_implied_upper(npp, q, uu);
+ xassert(0 <= ub_changed && ub_changed <= 4);
+ if (ub_changed == 4) return 4; /* infeasible */
+ }
+ /* if neither lower nor upper column bound was changed, the row
+ is originally redundant and can be replaced by free row */
+ if (!lb_changed && !ub_changed)
+ { p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ npp_free_row(npp, p);
+ return 0;
+ }
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_ineq_singlet, sizeof(struct ineq_singlet));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = apq->val;
+ info->c = q->coef;
+ info->lb = p->lb;
+ info->ub = p->ub;
+ info->lb_changed = (char)lb_changed;
+ info->ub_changed = (char)ub_changed;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q], i != p (not needed for MIP
+ solution) */
+ if (npp->sol != GLP_MIP)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return lb_changed >= ub_changed ? lb_changed : ub_changed;
+}
+
+static int rcv_ineq_singlet(NPP *npp, void *_info)
+{ /* recover row singleton (inequality constraint) */
+ struct ineq_singlet *info = _info;
+ NPPLFE *lfe;
+ double lambda;
+ if (npp->sol == GLP_MIP) goto done;
+ /* compute lambda~[q] in solution to the transformed problem
+ with formula (8) */
+ lambda = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ lambda -= lfe->val * npp->r_pi[lfe->ref];
+ if (npp->sol == GLP_SOL)
+ { /* recover basic solution */
+ if (npp->c_stat[info->q] == GLP_BS)
+ { /* column q is basic, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+nl: { /* column q is non-basic with lower bound active */
+ if (info->lb_changed)
+ { /* it is implied bound, so actually row p is active
+ while column q is basic */
+ npp->r_stat[info->p] =
+ (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* it is original bound, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NU)
+nu: { /* column q is non-basic with upper bound active */
+ if (info->ub_changed)
+ { /* it is implied bound, so actually row p is active
+ while column q is basic */
+ npp->r_stat[info->p] =
+ (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* it is original bound, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NS)
+ { /* column q is non-basic and fixed; note, however, that in
+ in the original problem it is non-fixed */
+ if (lambda > +1e-7)
+ { if (info->apq > 0.0 && info->lb != -DBL_MAX ||
+ info->apq < 0.0 && info->ub != +DBL_MAX ||
+ !info->lb_changed)
+ { /* either corresponding bound of row p exists or
+ column q remains non-basic with its original lower
+ bound active */
+ npp->c_stat[info->q] = GLP_NL;
+ goto nl;
+ }
+ }
+ if (lambda < -1e-7)
+ { if (info->apq > 0.0 && info->ub != +DBL_MAX ||
+ info->apq < 0.0 && info->lb != -DBL_MAX ||
+ !info->ub_changed)
+ { /* either corresponding bound of row p exists or
+ column q remains non-basic with its original upper
+ bound active */
+ npp->c_stat[info->q] = GLP_NU;
+ goto nu;
+ }
+ }
+ /* either lambda~[q] is close to zero, or corresponding
+ bound of row p does not exist, because lambda~[q] has
+ wrong sign due to round-off errors; in the latter case
+ lambda~[q] is also assumed to be close to zero; so, we
+ can make row p active on its existing bound and column q
+ basic; pi[p] will have wrong sign, but it also will be
+ close to zero (rarus casus of dual degeneracy) */
+ if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
+ { /* row lower bound exists, but upper bound doesn't */
+ npp->r_stat[info->p] = GLP_NL;
+ }
+ else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
+ { /* row upper bound exists, but lower bound doesn't */
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
+ { /* both row lower and upper bounds exist */
+ /* to choose proper active row bound we should not use
+ lambda~[q], because its value being close to zero is
+ unreliable; so we choose that bound which provides
+ primal feasibility for original constraint (1) */
+ if (info->apq * npp->c_value[info->q] <=
+ 0.5 * (info->lb + info->ub))
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ if (npp->sol == GLP_IPT)
+ { /* recover interior-point solution */
+ if (lambda > +DBL_EPSILON && info->lb_changed ||
+ lambda < -DBL_EPSILON && info->ub_changed)
+ { /* actually row p has corresponding active bound */
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* either bounds of column q are both inactive or its
+ original bound is active */
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+done: return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_slack - process column singleton (implied slack variable)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_implied_slack(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_slack processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], having the only non-zero coefficient in row p,
+* which is equality constraint:
+*
+* sum a[p,j] x[j] + a[p,q] x[q] = b. (2)
+* j!=q
+*
+* PROBLEM TRANSFORMATION
+*
+* (If x[q] is integral, this transformation must not be used.)
+*
+* The term a[p,q] x[q] in constraint (2) can be considered as a slack
+* variable that allows to carry bounds of column q over row p and then
+* remove column q from the problem.
+*
+* Constraint (2) can be written as follows:
+*
+* sum a[p,j] x[j] = b - a[p,q] x[q]. (3)
+* j!=q
+*
+* According to (1) constraint (3) is equivalent to the following
+* inequality constraint:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (4)
+* j!=q
+*
+* where
+*
+* ( b - a[p,q] u[q], if a[p,q] > 0
+* L[p] = < (5)
+* ( b - a[p,q] l[q], if a[p,q] < 0
+*
+* ( b - a[p,q] l[q], if a[p,q] > 0
+* U[p] = < (6)
+* ( b - a[p,q] u[q], if a[p,q] < 0
+*
+* From (2) it follows that:
+*
+* 1
+* x[q] = ------ (b - sum a[p,j] x[j]). (7)
+* a[p,q] j!=q
+*
+* In order to eliminate x[q] from the objective row we substitute it
+* from (6) to that row:
+*
+* z = sum c[j] x[j] + c[q] x[q] + c[0] =
+* j!=q
+* 1
+* = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
+* j!=q a[p,q] j!=q
+*
+* = sum c~[j] x[j] + c~[0],
+* j!=q
+* a[p,j] b
+* c~[j] = c[j] - c[q] ------, c~0 = c0 - c[q] ------ (8)
+* a[p,q] a[p,q]
+*
+* are values of objective coefficients and constant term, resp., in
+* the transformed problem.
+*
+* Note that column q is column singleton, so in the dual system of the
+* original problem it corresponds to the following row singleton:
+*
+* a[p,q] pi[p] + lambda[q] = c[q]. (9)
+*
+* In the transformed problem row (9) would be the following:
+*
+* a[p,q] pi~[p] + lambda[q] = c~[q] = 0. (10)
+*
+* Subtracting (10) from (9) we have:
+*
+* a[p,q] (pi[p] - pi~[p]) = c[q]
+*
+* that gives the following formula to compute multiplier for row p in
+* solution to the original problem using its value in solution to the
+* transformed problem:
+*
+* pi[p] = pi~[p] + c[q] / a[p,q]. (11)
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is defined
+* by status of row p in solution to the transformed problem and the
+* sign of coefficient a[p,q] in the original inequality constraint (2)
+* as follows:
+*
+* +-----------------------+---------+--------------------+
+* | Status of row p | Sign of | Status of column q |
+* | (transformed problem) | a[p,q] | (original problem) |
+* +-----------------------+---------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NL | + | GLP_NU |
+* | GLP_NL | - | GLP_NL |
+* | GLP_NU | + | GLP_NL |
+* | GLP_NU | - | GLP_NU |
+* | GLP_NF | + / - | GLP_NF |
+* +-----------------------+---------+--------------------+
+*
+* Value of column q is computed with formula (7). Since originally row
+* p is equality constraint, its status is assigned GLP_NS, and value of
+* its multiplier pi[p] is computed with formula (11).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (7). Row multiplier value
+* pi[p] is computed with formula (11).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (7). */
+
+struct implied_slack
+{ /* column singleton (implied slack variable) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double b;
+ /* right-hand side of original equality constraint */
+ double c;
+ /* original objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[p,j], j != q */
+};
+
+static int rcv_implied_slack(NPP *npp, void *info);
+
+void npp_implied_slack(NPP *npp, NPPCOL *q)
+{ /* process column singleton (implied slack variable) */
+ struct implied_slack *info;
+ NPPROW *p;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ /* the column must be non-integral non-fixed singleton */
+ xassert(!q->is_int);
+ xassert(q->lb < q->ub);
+ xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+ /* corresponding row must be equality constraint */
+ aij = q->ptr;
+ p = aij->row;
+ xassert(p->lb == p->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_implied_slack, sizeof(struct implied_slack));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = aij->val;
+ info->b = p->lb;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save row coefficients a[p,j], j != q, and substitute x[q]
+ into the objective row */
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->col == q) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->col->j;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ aij->col->coef -= info->c * (aij->val / info->apq);
+ }
+ npp->c0 += info->c * (info->b / info->apq);
+ /* compute new row bounds */
+ if (info->apq > 0.0)
+ { p->lb = (q->ub == +DBL_MAX ?
+ -DBL_MAX : info->b - info->apq * q->ub);
+ p->ub = (q->lb == -DBL_MAX ?
+ +DBL_MAX : info->b - info->apq * q->lb);
+ }
+ else
+ { p->lb = (q->lb == -DBL_MAX ?
+ -DBL_MAX : info->b - info->apq * q->lb);
+ p->ub = (q->ub == +DBL_MAX ?
+ +DBL_MAX : info->b - info->apq * q->ub);
+ }
+ /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return;
+}
+
+static int rcv_implied_slack(NPP *npp, void *_info)
+{ /* recover column singleton (implied slack variable) */
+ struct implied_slack *info = _info;
+ NPPLFE *lfe;
+ double temp;
+ if (npp->sol == GLP_SOL)
+ { /* assign statuses to row p and column q */
+ if (npp->r_stat[info->p] == GLP_BS ||
+ npp->r_stat[info->p] == GLP_NF)
+ npp->c_stat[info->q] = npp->r_stat[info->p];
+ else if (npp->r_stat[info->p] == GLP_NL)
+ npp->c_stat[info->q] =
+ (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+ else if (npp->r_stat[info->p] == GLP_NU)
+ npp->c_stat[info->q] =
+ (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+ else
+ { npp_error();
+ return 1;
+ }
+ npp->r_stat[info->p] = GLP_NS;
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute multiplier for row p */
+ npp->r_pi[info->p] += info->c / info->apq;
+ }
+ /* compute value of column q */
+ temp = info->b;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ temp -= lfe->val * npp->c_value[lfe->ref];
+ npp->c_value[info->q] = temp / info->apq;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_free - process column singleton (implied free variable)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_free(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_free processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* having non-zero coefficient in the only row p, which is inequality
+* constraint:
+*
+* L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p], (2)
+* j!=q
+*
+* where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - column lower and/or upper bound(s) can be active;
+*
+* 2 - problem has no dual feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (2) can be written as follows:
+*
+* L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
+* j!=q j!=q
+*
+* from which it follows that:
+*
+* alfa <= a[p,q] x[q] <= beta, (3)
+*
+* where
+*
+* alfa = inf(L[p] - sum a[p,j] x[j]) =
+* j!=q
+*
+* = L[p] - sup sum a[p,j] x[j] = (4)
+* j!=q
+*
+* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* beta = sup(L[p] - sum a[p,j] x[j]) =
+* j!=q
+*
+* = L[p] - inf sum a[p,j] x[j] = (5)
+* j!=q
+*
+* = L[p] - sum a[p,j] l[j] - sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* Jp = {j != q: a[p,j] > 0}, Jn = {j != q: a[p,j] < 0}. (6)
+*
+* Inequality (3) defines implied bounds of variable x[q]:
+*
+* l'[q] <= x[q] <= u'[q], (7)
+*
+* where
+*
+* ( alfa / a[p,q], if a[p,q] > 0
+* l'[q] = < (8a)
+* ( beta / a[p,q], if a[p,q] < 0
+*
+* ( beta / a[p,q], if a[p,q] > 0
+* u'[q] = < (8b)
+* ( alfa / a[p,q], if a[p,q] < 0
+*
+* Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
+* an absolute tolerance for column value, column bounds (1) cannot be
+* active, in which case column q can be replaced by equivalent free
+* (unbounded) column.
+*
+* Note that column q is column singleton, so in the dual system of the
+* original problem it corresponds to the following row singleton:
+*
+* a[p,q] pi[p] + lambda[q] = c[q], (9)
+*
+* from which it follows that:
+*
+* pi[p] = (c[q] - lambda[q]) / a[p,q]. (10)
+*
+* Let x[q] be implied free (unbounded) variable. Then column q can be
+* only basic, so its multiplier lambda[q] is equal to zero, and from
+* (10) we have:
+*
+* pi[p] = c[q] / a[p,q]. (11)
+*
+* There are possible three cases:
+*
+* 1) pi[p] < -eps, where eps is an absolute tolerance for row
+* multiplier. In this case, to provide dual feasibility of the
+* original problem, row p must be active on its lower bound, and
+* if its lower bound does not exist (L[p] = -oo), the problem has
+* no dual feasible solution;
+*
+* 2) pi[p] > +eps. In this case row p must be active on its upper
+* bound, and if its upper bound does not exist (U[p] = +oo), the
+* problem has no dual feasible solution;
+*
+* 3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
+* bound of row p can be active, because this does not affect dual
+* feasibility.
+*
+* Thus, in all three cases original inequality constraint (2) can be
+* replaced by equality constraint, where the right-hand side is either
+* lower or upper bound of row p, and bounds of column q can be removed
+* that makes it free (unbounded). (May note that this transformation
+* can be followed by transformation "Column singleton (implied slack
+* variable)" performed by the routine npp_implied_slack.)
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status in solution to the transformed problem and its bound,
+* which was choosen to be active:
+*
+* +-----------------------+--------+--------------------+
+* | Status of row p | Active | Status of row p |
+* | (transformed problem) | bound | (original problem) |
+* +-----------------------+--------+--------------------+
+* | GLP_BS | L[p] | GLP_BS |
+* | GLP_BS | U[p] | GLP_BS |
+* | GLP_NS | L[p] | GLP_NL |
+* | GLP_NS | U[p] | GLP_NU |
+* +-----------------------+--------+--------------------+
+*
+* Value of row multiplier pi[p] (as well as value of column q) in
+* solution to the original problem is the same as in solution to the
+* transformed problem.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct implied_free
+{ /* column singleton (implied free variable) */
+ int p;
+ /* row reference number */
+ char stat;
+ /* row status:
+ GLP_NL - active constraint on lower bound
+ GLP_NU - active constraint on upper bound */
+};
+
+static int rcv_implied_free(NPP *npp, void *info);
+
+int npp_implied_free(NPP *npp, NPPCOL *q)
+{ /* process column singleton (implied free variable) */
+ struct implied_free *info;
+ NPPROW *p;
+ NPPAIJ *apq, *aij;
+ double alfa, beta, l, u, pi, eps;
+ /* the column must be non-fixed singleton */
+ xassert(q->lb < q->ub);
+ xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+ /* corresponding row must be inequality constraint */
+ apq = q->ptr;
+ p = apq->row;
+ xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* compute alfa */
+ alfa = p->lb;
+ if (alfa != -DBL_MAX)
+ { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ if (aij->val > 0.0)
+ { if (aij->col->ub == +DBL_MAX)
+ { alfa = -DBL_MAX;
+ break;
+ }
+ alfa -= aij->val * aij->col->ub;
+ }
+ else /* < 0.0 */
+ { if (aij->col->lb == -DBL_MAX)
+ { alfa = -DBL_MAX;
+ break;
+ }
+ alfa -= aij->val * aij->col->lb;
+ }
+ }
+ }
+ /* compute beta */
+ beta = p->ub;
+ if (beta != +DBL_MAX)
+ { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ if (aij->val > 0.0)
+ { if (aij->col->lb == -DBL_MAX)
+ { beta = +DBL_MAX;
+ break;
+ }
+ beta -= aij->val * aij->col->lb;
+ }
+ else /* < 0.0 */
+ { if (aij->col->ub == +DBL_MAX)
+ { beta = +DBL_MAX;
+ break;
+ }
+ beta -= aij->val * aij->col->ub;
+ }
+ }
+ }
+ /* compute implied column lower bound l'[q] */
+ if (apq->val > 0.0)
+ l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
+ else /* < 0.0 */
+ l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
+ /* compute implied column upper bound u'[q] */
+ if (apq->val > 0.0)
+ u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
+ else
+ u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
+ /* check if column lower bound l[q] can be active */
+ if (q->lb != -DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(q->lb);
+ if (l < q->lb - eps) return 1; /* yes, it can */
+ }
+ /* check if column upper bound u[q] can be active */
+ if (q->ub != +DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(q->ub);
+ if (u > q->ub + eps) return 1; /* yes, it can */
+ }
+ /* okay; make column q free (unbounded) */
+ q->lb = -DBL_MAX, q->ub = +DBL_MAX;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_implied_free, sizeof(struct implied_free));
+ info->p = p->i;
+ info->stat = -1;
+ /* compute row multiplier pi[p] */
+ pi = q->coef / apq->val;
+ /* check dual feasibility for row p */
+ if (pi > +DBL_EPSILON)
+ { /* lower bound L[p] must be active */
+ if (p->lb != -DBL_MAX)
+nl: { info->stat = GLP_NL;
+ p->ub = p->lb;
+ }
+ else
+ { if (pi > +1e-5) return 2; /* dual infeasibility */
+ /* take a chance on U[p] */
+ xassert(p->ub != +DBL_MAX);
+ goto nu;
+ }
+ }
+ else if (pi < -DBL_EPSILON)
+ { /* upper bound U[p] must be active */
+ if (p->ub != +DBL_MAX)
+nu: { info->stat = GLP_NU;
+ p->lb = p->ub;
+ }
+ else
+ { if (pi < -1e-5) return 2; /* dual infeasibility */
+ /* take a chance on L[p] */
+ xassert(p->lb != -DBL_MAX);
+ goto nl;
+ }
+ }
+ else
+ { /* any bound (either L[p] or U[p]) can be made active */
+ if (p->ub == +DBL_MAX)
+ { xassert(p->lb != -DBL_MAX);
+ goto nl;
+ }
+ if (p->lb == -DBL_MAX)
+ { xassert(p->ub != +DBL_MAX);
+ goto nu;
+ }
+ if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
+ }
+ return 0;
+}
+
+static int rcv_implied_free(NPP *npp, void *_info)
+{ /* recover column singleton (implied free variable) */
+ struct implied_free *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { xassert(info->stat == GLP_NL || info->stat == GLP_NU);
+ npp->r_stat[info->p] = info->stat;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_eq_doublet - process row doubleton (equality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_eq_doublet processes row p, which is equality
+* constraint having exactly two non-zero coefficients:
+*
+* a[p,q] x[q] + a[p,r] x[r] = b. (1)
+*
+* As the result of processing one of columns q or r is eliminated from
+* all other rows and, thus, becomes column singleton of type "implied
+* slack variable". Row p is not changed and along with column q and r
+* remains in the problem.
+*
+* RETURNS
+*
+* The routine npp_eq_doublet returns pointer to the descriptor of that
+* column q or r which has been eliminated. If, due to some reason, the
+* elimination was not performed, the routine returns NULL.
+*
+* PROBLEM TRANSFORMATION
+*
+* First, we decide which column q or r will be eliminated. Let it be
+* column q. Consider i-th constraint row, where column q has non-zero
+* coefficient a[i,q] != 0:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i]. (2)
+* j
+*
+* In order to eliminate column q from row (2) we subtract from it row
+* (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
+* transformed problem row (2) by its linear combination with row (1).
+* This transformation changes only coefficients in columns q and r,
+* and bounds of row i as follows:
+*
+* a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0, (3)
+*
+* a~[i,r] = a[i,r] - gamma[i] a[p,r], (4)
+*
+* L~[i] = L[i] - gamma[i] b, (5)
+*
+* U~[i] = U[i] - gamma[i] b. (6)
+*
+* RECOVERING BASIC SOLUTION
+*
+* The transformation of the primal system of the original problem:
+*
+* L <= A x <= U (7)
+*
+* is equivalent to multiplying from the left a transformation matrix F
+* by components of this primal system, which in the transformed problem
+* becomes the following:
+*
+* F L <= F A x <= F U ==> L~ <= A~x <= U~. (8)
+*
+* The matrix F has the following structure:
+*
+* ( 1 -gamma[1] )
+* ( )
+* ( 1 -gamma[2] )
+* ( )
+* ( ... ... )
+* ( )
+* F = ( 1 -gamma[p-1] ) (9)
+* ( )
+* ( 1 )
+* ( )
+* ( -gamma[p+1] 1 )
+* ( )
+* ( ... ... )
+*
+* where its column containing elements -gamma[i] corresponds to row p
+* of the primal system.
+*
+* From (8) it follows that the dual system of the original problem:
+*
+* A'pi + lambda = c, (10)
+*
+* in the transformed problem becomes the following:
+*
+* A'F'inv(F')pi + lambda = c ==> (A~)'pi~ + lambda = c, (11)
+*
+* where:
+*
+* pi~ = inv(F')pi (12)
+*
+* is the vector of row multipliers in the transformed problem. Thus:
+*
+* pi = F'pi~. (13)
+*
+* Therefore, as it follows from (13), value of multiplier for row p in
+* solution to the original problem can be computed as follows:
+*
+* pi[p] = pi~[p] - sum gamma[i] pi~[i], (14)
+* i
+*
+* where pi~[i] = pi[i] is multiplier for row i (i != p).
+*
+* Note that the statuses of all rows and columns are not changed.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Multiplier for row p in solution to the original problem is computed
+* with formula (14).
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct eq_doublet
+{ /* row doubleton (equality constraint) */
+ int p;
+ /* row reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_doublet(NPP *npp, void *info);
+
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
+{ /* process row doubleton (equality constraint) */
+ struct eq_doublet *info;
+ NPPROW *i;
+ NPPCOL *q, *r;
+ NPPAIJ *apq, *apr, *aiq, *air, *next;
+ NPPLFE *lfe;
+ double gamma;
+ /* the row must be doubleton equality constraint */
+ xassert(p->lb == p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
+ p->ptr->r_next->r_next == NULL);
+ /* choose column to be eliminated */
+ { NPPAIJ *a1, *a2;
+ a1 = p->ptr, a2 = a1->r_next;
+ if (fabs(a2->val) < 0.001 * fabs(a1->val))
+ { /* only first column can be eliminated, because second one
+ has too small constraint coefficient */
+ apq = a1, apr = a2;
+ }
+ else if (fabs(a1->val) < 0.001 * fabs(a2->val))
+ { /* only second column can be eliminated, because first one
+ has too small constraint coefficient */
+ apq = a2, apr = a1;
+ }
+ else
+ { /* both columns are appropriate; choose that one which is
+ shorter to minimize fill-in */
+ if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
+ { /* first column is shorter */
+ apq = a1, apr = a2;
+ }
+ else
+ { /* second column is shorter */
+ apq = a2, apr = a1;
+ }
+ }
+ }
+ /* now columns q and r have been chosen */
+ q = apq->col, r = apr->col;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_eq_doublet, sizeof(struct eq_doublet));
+ info->p = p->i;
+ info->apq = apq->val;
+ info->ptr = NULL;
+ /* transform each row i (i != p), where a[i,q] != 0, to eliminate
+ column q */
+ for (aiq = q->ptr; aiq != NULL; aiq = next)
+ { next = aiq->c_next;
+ if (aiq == apq) continue; /* skip row p */
+ i = aiq->row; /* row i to be transformed */
+ /* save constraint coefficient a[i,q] */
+ if (npp->sol != GLP_MIP)
+ { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = i->i;
+ lfe->val = aiq->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ /* find coefficient a[i,r] in row i */
+ for (air = i->ptr; air != NULL; air = air->r_next)
+ if (air->col == r) break;
+ /* if a[i,r] does not exist, create a[i,r] = 0 */
+ if (air == NULL)
+ air = npp_add_aij(npp, i, r, 0.0);
+ /* compute gamma[i] = a[i,q] / a[p,q] */
+ gamma = aiq->val / apq->val;
+ /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
+ /* new a[i,q] is exact zero due to elimnation; remove it from
+ row i */
+ npp_del_aij(npp, aiq);
+ /* compute new a[i,r] */
+ air->val -= gamma * apr->val;
+ /* if new a[i,r] is close to zero due to numeric cancelation,
+ remove it from row i */
+ if (fabs(air->val) <= 1e-10)
+ npp_del_aij(npp, air);
+ /* compute new lower and upper bounds of row i */
+ if (i->lb == i->ub)
+ i->lb = i->ub = (i->lb - gamma * p->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= gamma * p->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= gamma * p->lb;
+ }
+ }
+ return q;
+}
+
+static int rcv_eq_doublet(NPP *npp, void *_info)
+{ /* recover row doubleton (equality constraint) */
+ struct eq_doublet *info = _info;
+ NPPLFE *lfe;
+ double gamma, temp;
+ /* we assume that processing row p is followed by processing
+ column q as singleton of type "implied slack variable", in
+ which case row p must always be active equality constraint */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute value of multiplier for row p; see (14) */
+ temp = npp->r_pi[info->p];
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ { gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
+ temp -= gamma * npp->r_pi[lfe->ref];
+ }
+ npp->r_pi[info->p] = temp;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_forcing_row - process forcing row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+*
+* DESCRIPTION
+*
+* The routine npp_forcing row processes row p of general format:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
+* assumed that:
+*
+* 1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
+* row upper bound (see below), eps is an absolute tolerance for row
+* value;
+*
+* 2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
+* row lower bound (see below).
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - cannot fix columns due to too small constraint coefficients.
+*
+* PROBLEM TRANSFORMATION
+*
+* Implied lower and upper bounds of row (1) are determined by bounds
+* of corresponding columns (variables) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
+* all variables take their boundary values as defined by (4):
+*
+* ( u[j], if j in Jp
+* x[j] = < (6)
+* ( l[j], if j in Jn
+*
+* Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
+* only when all variables take their boundary values as defined by (3):
+*
+* ( l[j], if j in Jp
+* x[j] = < (7)
+* ( u[j], if j in Jn
+*
+* Condition (6) or (7) allows fixing all columns (variables x[j])
+* in row (1) on their bounds and then removing them from the problem
+* (see the routine npp_fixed_col). Due to this row p becomes redundant,
+* so it can be replaced by equivalent free (unbounded) row and also
+* removed from the problem (see the routine npp_free_row).
+*
+* 1. To apply this transformation row (1) should not have coefficients
+* whose magnitude is too small, i.e. all a[p,j] should satisfy to
+* the following condition:
+*
+* |a[p,j]| >= eps * max(1, |a[p,k]|), (8)
+* k
+* where eps is a relative tolerance for constraint coefficients.
+* Otherwise, fixing columns may be numerically unreliable and may
+* lead to wrong solution.
+*
+* 2. The routine fixes columns and remove bounds of row p, however,
+* it does not remove the row and columns from the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In the transformed problem row p being inactive constraint is
+* assigned status GLP_BS (as the result of transformation of free
+* row), and all columns in this row are assigned status GLP_NS (as the
+* result of transformation of fixed columns).
+*
+* Note that in the dual system of the transformed (as well as original)
+* problem every column j in row p corresponds to the following row:
+*
+* sum a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j], (9)
+* i!=p
+*
+* from which it follows that:
+*
+* lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p]. (10)
+* i!=p
+*
+* In the transformed problem values of all multipliers pi[i] are known
+* (including pi[i], whose value is zero, since row p is inactive).
+* Thus, using formula (10) it is possible to compute values of
+* multipliers lambda[j] for all columns in row p.
+*
+* Note also that in the original problem all columns in row p are
+* bounded, not fixed. So status GLP_NS assigned to every such column
+* must be changed to GLP_NL or GLP_NU depending on which bound the
+* corresponding column has been fixed. This status change may lead to
+* dual feasibility violation for solution of the original problem,
+* because now column multipliers must satisfy to the following
+* condition:
+*
+* ( >= 0, if status of column j is GLP_NL,
+* lambda[j] < (11)
+* ( <= 0, if status of column j is GLP_NU.
+*
+* If this condition holds, solution to the original problem is the
+* same as to the transformed problem. Otherwise, we have to perform
+* one degenerate pivoting step of the primal simplex method to obtain
+* dual feasible (hence, optimal) solution to the original problem as
+* follows. If, on problem transformation, row p was made active on its
+* lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
+* and start increasing its multiplier pi[p]. Otherwise, if row p was
+* made active on its upper bound (case at = 1), we change its status
+* to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
+* follows that:
+*
+* delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p]. (12)
+*
+* Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
+* specified direction causes increasing lambda[j] for every column j
+* assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
+* for every column j assigned status GLP_NU (delta lambda[j] < 0). It
+* is understood that once the last lambda[q], which violates condition
+* (11), has reached zero, multipliers lambda[j] for all columns get
+* valid signs. Such column q can be determined as follows. Let d[j] be
+* initial value of lambda[j] (i.e. reduced cost of column j) in the
+* transformed problem computed with formula (10) when pi[p] = 0. Then
+* lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
+* lambda[j] becomes zero if:
+*
+* delta lambda[j] = - a[p,j] pi[p] = - d[j] ==>
+* (13)
+* pi[p] = d[j] / a[p,j].
+*
+* Therefore, the last column q, for which lambda[q] becomes zero, can
+* be determined from the following condition:
+*
+* |d[q] / a[p,q]| = max |pi[p]| = max |d[j] / a[p,j]|, (14)
+* j in D j in D
+*
+* where D is a set of columns j whose, reduced costs d[j] have invalid
+* signs, i.e. violate condition (11). (Thus, if D is empty, solution
+* to the original problem is the same as solution to the transformed
+* problem, and no correction is needed as was noticed above.) In
+* solution to the original problem column q is assigned status GLP_BS,
+* since it replaces column of auxiliary variable of row p (becoming
+* active) in the basis, and multiplier for row p is assigned its new
+* value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
+* degeneracy values of all columns having non-zero coefficients in row
+* p remain unchanged.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of multiplier pi[p] in solution to the original problem is
+* corrected in the same way as for basic solution. Values of all
+* columns having non-zero coefficients in row p remain unchanged.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct forcing_col
+{ /* column fixed on its bound by forcing row */
+ int j;
+ /* column reference number */
+ char stat;
+ /* original column status:
+ GLP_NL - fixed on lower bound
+ GLP_NU - fixed on upper bound */
+ double a;
+ /* constraint coefficient a[p,j] */
+ double c;
+ /* objective coefficient c[j] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,j], i != p */
+ struct forcing_col *next;
+ /* pointer to another column fixed by forcing row */
+};
+
+struct forcing_row
+{ /* forcing row */
+ int p;
+ /* row reference number */
+ char stat;
+ /* status assigned to the row if it becomes active:
+ GLP_NS - active equality constraint
+ GLP_NL - inequality constraint with lower bound active
+ GLP_NU - inequality constraint with upper bound active */
+ struct forcing_col *ptr;
+ /* list of all columns having non-zero constraint coefficient
+ a[p,j] in the forcing row */
+};
+
+static int rcv_forcing_row(NPP *npp, void *info);
+
+int npp_forcing_row(NPP *npp, NPPROW *p, int at)
+{ /* process forcing row */
+ struct forcing_row *info;
+ struct forcing_col *col = NULL;
+ NPPCOL *j;
+ NPPAIJ *apj, *aij;
+ NPPLFE *lfe;
+ double big;
+ xassert(at == 0 || at == 1);
+ /* determine maximal magnitude of the row coefficients */
+ big = 1.0;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ if (big < fabs(apj->val)) big = fabs(apj->val);
+ /* if there are too small coefficients in the row, transformation
+ should not be applied */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ if (fabs(apj->val) < 1e-7 * big) return 1;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_forcing_row, sizeof(struct forcing_row));
+ info->p = p->i;
+ if (p->lb == p->ub)
+ { /* equality constraint */
+ info->stat = GLP_NS;
+ }
+ else if (at == 0)
+ { /* inequality constraint; case L[p] = U'[p] */
+ info->stat = GLP_NL;
+ xassert(p->lb != -DBL_MAX);
+ }
+ else /* at == 1 */
+ { /* inequality constraint; case U[p] = L'[p] */
+ info->stat = GLP_NU;
+ xassert(p->ub != +DBL_MAX);
+ }
+ info->ptr = NULL;
+ /* scan the forcing row, fix columns at corresponding bounds, and
+ save column information (the latter is not needed for MIP) */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { /* column j has non-zero coefficient in the forcing row */
+ j = apj->col;
+ /* it must be non-fixed */
+ xassert(j->lb < j->ub);
+ /* allocate stack entry to save column information */
+ if (npp->sol != GLP_MIP)
+ { col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
+ col->j = j->j;
+ col->stat = -1; /* will be set below */
+ col->a = apj->val;
+ col->c = j->coef;
+ col->ptr = NULL;
+ col->next = info->ptr;
+ info->ptr = col;
+ }
+ /* fix column j */
+ if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
+ { /* at its lower bound */
+ if (npp->sol != GLP_MIP)
+ col->stat = GLP_NL;
+ xassert(j->lb != -DBL_MAX);
+ j->ub = j->lb;
+ }
+ else
+ { /* at its upper bound */
+ if (npp->sol != GLP_MIP)
+ col->stat = GLP_NU;
+ xassert(j->ub != +DBL_MAX);
+ j->lb = j->ub;
+ }
+ /* save column coefficients a[i,j], i != p */
+ if (npp->sol != GLP_MIP)
+ { for (aij = j->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij == apj) continue; /* skip a[p,j] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = col->ptr;
+ col->ptr = lfe;
+ }
+ }
+ }
+ /* make the row free (unbounded) */
+ p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ return 0;
+}
+
+static int rcv_forcing_row(NPP *npp, void *_info)
+{ /* recover forcing row */
+ struct forcing_row *info = _info;
+ struct forcing_col *col, *piv;
+ NPPLFE *lfe;
+ double d, big, temp;
+ if (npp->sol == GLP_MIP) goto done;
+ /* initially solution to the original problem is the same as
+ to the transformed problem, where row p is inactive constraint
+ with pi[p] = 0, and all columns are non-basic */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] != GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ for (col = info->ptr; col != NULL; col = col->next)
+ { if (npp->c_stat[col->j] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ npp->c_stat[col->j] = col->stat; /* original status */
+ }
+ }
+ /* compute reduced costs d[j] for all columns with formula (10)
+ and store them in col.c instead objective coefficients */
+ for (col = info->ptr; col != NULL; col = col->next)
+ { d = col->c;
+ for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
+ d -= lfe->val * npp->r_pi[lfe->ref];
+ col->c = d;
+ }
+ /* consider columns j, whose multipliers lambda[j] has wrong
+ sign in solution to the transformed problem (where lambda[j] =
+ d[j]), and choose column q, whose multipler lambda[q] reaches
+ zero last on changing row multiplier pi[p]; see (14) */
+ piv = NULL, big = 0.0;
+ for (col = info->ptr; col != NULL; col = col->next)
+ { d = col->c; /* d[j] */
+ temp = fabs(d / col->a);
+ if (col->stat == GLP_NL)
+ { /* column j has active lower bound */
+ if (d < 0.0 && big < temp)
+ piv = col, big = temp;
+ }
+ else if (col->stat == GLP_NU)
+ { /* column j has active upper bound */
+ if (d > 0.0 && big < temp)
+ piv = col, big = temp;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* if column q does not exist, no correction is needed */
+ if (piv != NULL)
+ { /* correct solution; row p becomes active constraint while
+ column q becomes basic */
+ if (npp->sol == GLP_SOL)
+ { npp->r_stat[info->p] = info->stat;
+ npp->c_stat[piv->j] = GLP_BS;
+ }
+ /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
+ npp->r_pi[info->p] = piv->c / piv->a;
+ }
+done: return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_analyze_row - perform general row analysis
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_analyze_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_analyze_row performs analysis of row p of general
+* format:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
+*
+* RETURNS
+*
+* 0x?0 - row lower bound does not exist or is redundant;
+*
+* 0x?1 - row lower bound can be active;
+*
+* 0x?2 - row lower bound is a forcing bound;
+*
+* 0x0? - row upper bound does not exist or is redundant;
+*
+* 0x1? - row upper bound can be active;
+*
+* 0x2? - row upper bound is a forcing bound;
+*
+* 0x33 - row bounds are inconsistent with column bounds.
+*
+* ALGORITHM
+*
+* Analysis of row (1) is based on analysis of its implied lower and
+* upper bounds, which are determined by bounds of corresponding columns
+* (variables) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* (Note that bounds of all columns in row p are assumed to be correct,
+* so L'[p] <= U'[p].)
+*
+* Analysis of row lower bound L[p] includes the following cases:
+*
+* 1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
+* value, row lower bound L[p] and implied row upper bound U'[p] are
+* inconsistent, ergo, the problem has no primal feasible solution;
+*
+* 2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
+* the row is a forcing row on its lower bound (see description of
+* the routine npp_forcing_row);
+*
+* 3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
+* conclusion does not account other rows in the problem);
+*
+* 4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
+* it is redundant and can be removed (replaced by -oo).
+*
+* Analysis of row upper bound U[p] is performed in a similar way and
+* includes the following cases:
+*
+* 1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
+* bound L'[p] are inconsistent, ergo the problem has no primal
+* feasible solution;
+*
+* 2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
+* the row is a forcing row on its upper bound (see description of
+* the routine npp_forcing_row);
+*
+* 3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
+* conclusion does not account other rows in the problem);
+*
+* 4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
+* it is redundant and can be removed (replaced by +oo). */
+
+int npp_analyze_row(NPP *npp, NPPROW *p)
+{ /* perform general row analysis */
+ NPPAIJ *aij;
+ int ret = 0x00;
+ double l, u, eps;
+ xassert(npp == npp);
+ /* compute implied lower bound L'[p]; see (3) */
+ l = 0.0;
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ { if (aij->col->lb == -DBL_MAX)
+ { l = -DBL_MAX;
+ break;
+ }
+ l += aij->val * aij->col->lb;
+ }
+ else /* aij->val < 0.0 */
+ { if (aij->col->ub == +DBL_MAX)
+ { l = -DBL_MAX;
+ break;
+ }
+ l += aij->val * aij->col->ub;
+ }
+ }
+ /* compute implied upper bound U'[p]; see (4) */
+ u = 0.0;
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ { if (aij->col->ub == +DBL_MAX)
+ { u = +DBL_MAX;
+ break;
+ }
+ u += aij->val * aij->col->ub;
+ }
+ else /* aij->val < 0.0 */
+ { if (aij->col->lb == -DBL_MAX)
+ { u = +DBL_MAX;
+ break;
+ }
+ u += aij->val * aij->col->lb;
+ }
+ }
+ /* column bounds are assumed correct, so L'[p] <= U'[p] */
+ /* check if row lower bound is consistent */
+ if (p->lb != -DBL_MAX)
+ { eps = 1e-3 + 1e-6 * fabs(p->lb);
+ if (p->lb - eps > u)
+ { ret = 0x33;
+ goto done;
+ }
+ }
+ /* check if row upper bound is consistent */
+ if (p->ub != +DBL_MAX)
+ { eps = 1e-3 + 1e-6 * fabs(p->ub);
+ if (p->ub + eps < l)
+ { ret = 0x33;
+ goto done;
+ }
+ }
+ /* check if row lower bound can be active/forcing */
+ if (p->lb != -DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(p->lb);
+ if (p->lb - eps > l)
+ { if (p->lb + eps <= u)
+ ret |= 0x01;
+ else
+ ret |= 0x02;
+ }
+ }
+ /* check if row upper bound can be active/forcing */
+ if (p->ub != +DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(p->ub);
+ if (p->ub + eps < u)
+ { /* check if the upper bound is forcing */
+ if (p->ub - eps >= l)
+ ret |= 0x10;
+ else
+ ret |= 0x20;
+ }
+ }
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_inactive_bound - remove row lower/upper inactive bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+*
+* DESCRIPTION
+*
+* The routine npp_inactive_bound removes lower (if which = 0) or upper
+* (if which = 1) bound of row p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p],
+*
+* which (bound) is assumed to be redundant.
+*
+* PROBLEM TRANSFORMATION
+*
+* If which = 0, current lower bound L[p] of row p is assigned -oo.
+* If which = 1, current upper bound U[p] of row p is assigned +oo.
+*
+* RECOVERING BASIC SOLUTION
+*
+* If in solution to the transformed problem row p is inactive
+* constraint (GLP_BS), its status is not changed in solution to the
+* original problem. Otherwise, status of row p in solution to the
+* original problem is defined by its type before transformation and
+* its status in solution to the transformed problem as follows:
+*
+* +---------------------+-------+---------------+---------------+
+* | Row | Flag | Row status in | Row status in |
+* | type | which | transfmd soln | original soln |
+* +---------------------+-------+---------------+---------------+
+* | sum >= L[p] | 0 | GLP_NF | GLP_NL |
+* | sum <= U[p] | 1 | GLP_NF | GLP_NU |
+* | L[p] <= sum <= U[p] | 0 | GLP_NU | GLP_NU |
+* | L[p] <= sum <= U[p] | 1 | GLP_NL | GLP_NL |
+* | sum = L[p] = U[p] | 0 | GLP_NU | GLP_NS |
+* | sum = L[p] = U[p] | 1 | GLP_NL | GLP_NS |
+* +---------------------+-------+---------------+---------------+
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* None needed.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct inactive_bound
+{ /* row inactive bound */
+ int p;
+ /* row reference number */
+ char stat;
+ /* row status (if active constraint) */
+};
+
+static int rcv_inactive_bound(NPP *npp, void *info);
+
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
+{ /* remove row lower/upper inactive bound */
+ struct inactive_bound *info;
+ if (npp->sol == GLP_SOL)
+ { /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_inactive_bound, sizeof(struct inactive_bound));
+ info->p = p->i;
+ if (p->ub == +DBL_MAX)
+ info->stat = GLP_NL;
+ else if (p->lb == -DBL_MAX)
+ info->stat = GLP_NU;
+ else if (p->lb != p->ub)
+ info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
+ else
+ info->stat = GLP_NS;
+ }
+ /* remove row inactive bound */
+ if (which == 0)
+ { xassert(p->lb != -DBL_MAX);
+ p->lb = -DBL_MAX;
+ }
+ else if (which == 1)
+ { xassert(p->ub != +DBL_MAX);
+ p->ub = +DBL_MAX;
+ }
+ else
+ xassert(which != which);
+ return;
+}
+
+static int rcv_inactive_bound(NPP *npp, void *_info)
+{ /* recover row status */
+ struct inactive_bound *info = _info;
+ if (npp->sol != GLP_SOL)
+ { npp_error();
+ return 1;
+ }
+ if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ npp->r_stat[info->p] = info->stat;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_bounds - determine implied column bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_implied_bounds(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_bounds inspects general row (constraint) p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
+* implied bounds of columns (variables x[j]) in this row.
+*
+* The routine stores implied column bounds l'[j] and u'[j] in column
+* descriptors (NPPCOL); it does not change current column bounds l[j]
+* and u[j]. (Implied column bounds can be then used to strengthen the
+* current column bounds; see the routines npp_implied_lower and
+* npp_implied_upper).
+*
+* ALGORITHM
+*
+* Current column bounds (2) define implied lower and upper bounds of
+* row (1) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* (Note that bounds of all columns in row p are assumed to be correct,
+* so L'[p] <= U'[p].)
+*
+* If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
+* row (1) can be active, in which case such row defines implied bounds
+* of its variables.
+*
+* Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
+* Consider a case when row lower bound can be active (L[p] > L'[p]):
+*
+* sum a[p,j] x[j] >= L[p] ==>
+* j
+*
+* sum a[p,j] x[j] + a[p,k] x[k] >= L[p] ==>
+* j!=k
+* (6)
+* a[p,k] x[k] >= L[p] - sum a[p,j] x[j] ==>
+* j!=k
+*
+* a[p,k] x[k] >= L[p,k],
+*
+* where
+*
+* L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
+* j!=k
+*
+* = L[p] - sup sum a[p,j] x[j] = (7)
+* j!=k
+*
+* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
+* j in Jp\{k} j in Jn\{k}
+*
+* Thus:
+*
+* x[k] >= l'[k] = L[p,k] / a[p,k], if a[p,k] > 0, (8)
+*
+* x[k] <= u'[k] = L[p,k] / a[p,k], if a[p,k] < 0. (9)
+*
+* where l'[k] and u'[k] are implied lower and upper bounds of variable
+* x[k], resp.
+*
+* Now consider a similar case when row upper bound can be active
+* (U[p] < U'[p]):
+*
+* sum a[p,j] x[j] <= U[p] ==>
+* j
+*
+* sum a[p,j] x[j] + a[p,k] x[k] <= U[p] ==>
+* j!=k
+* (10)
+* a[p,k] x[k] <= U[p] - sum a[p,j] x[j] ==>
+* j!=k
+*
+* a[p,k] x[k] <= U[p,k],
+*
+* where:
+*
+* U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
+* j!=k
+*
+* = U[p] - inf sum a[p,j] x[j] = (11)
+* j!=k
+*
+* = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
+* j in Jp\{k} j in Jn\{k}
+*
+* Thus:
+*
+* x[k] <= u'[k] = U[p,k] / a[p,k], if a[p,k] > 0, (12)
+*
+* x[k] >= l'[k] = U[p,k] / a[p,k], if a[p,k] < 0. (13)
+*
+* Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
+* must not be too small in magnitude relatively to other non-zero
+* coefficients in row (1), i.e. the following condition must hold:
+*
+* |a[p,k]| >= eps * max(1, |a[p,j]|), (14)
+* j
+*
+* where eps is a relative tolerance for constraint coefficients.
+* Otherwise the implied column bounds can be numerical inreliable. For
+* example, using formula (8) for the following inequality constraint:
+*
+* 1e-12 x1 - x2 - x3 >= 0,
+*
+* where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
+* conclusion that x1 >= 0.
+*
+* Using formulae (8), (9), (12), and (13) to compute implied bounds
+* for one variable requires |J| operations, where J = {j: a[p,j] != 0},
+* because this needs computing L[p,k] and U[p,k]. Thus, computing
+* implied bounds for all variables in row (1) would require |J|^2
+* operations, that is not a good technique. However, the total number
+* of operations can be reduced to |J| as follows.
+*
+* Let a[p,k] > 0. Then from (7) and (11) we have:
+*
+* L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
+*
+* = L[p] - U'[p] + a[p,k] u[k],
+*
+* U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
+*
+* = U[p] - L'[p] + a[p,k] l[k],
+*
+* where L'[p] and U'[p] are implied row lower and upper bounds defined
+* by formulae (3) and (4). Substituting these expressions into (8) and
+* (12) gives:
+*
+* l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k], (15)
+*
+* u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k]. (16)
+*
+* Similarly, if a[p,k] < 0, according to (7) and (11) we have:
+*
+* L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
+*
+* = L[p] - U'[p] + a[p,k] l[k],
+*
+* U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
+*
+* = U[p] - L'[p] + a[p,k] u[k],
+*
+* and substituting these expressions into (8) and (12) gives:
+*
+* l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k], (17)
+*
+* u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k]. (18)
+*
+* Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
+* exist. However, if for some variable x[j] it happens that l[j] = -oo
+* and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
+* a[p,j] < 0) are undefined. Consider, therefore, the most general
+* situation, when some column bounds (2) may not exist.
+*
+* Let:
+*
+* J' = {j : (a[p,j] > 0 and l[j] = -oo) or
+* (19)
+* (a[p,j] < 0 and u[j] = +oo)}.
+*
+* Then (assuming that row upper bound U[p] can be active) the following
+* three cases are possible:
+*
+* 1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
+* in row (1) we can use formulae (16) and (17);
+*
+* 2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
+* so for variable x[k] we can use formulae (12) and (13). Note that
+* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
+* or u'[j] = +oo (if a[p,j] > 0);
+*
+* 3) |J'| > 1. In this case for all variables x[j] in row [1] we have
+* l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
+*
+* Similarly, let:
+*
+* J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
+* (20)
+* (a[p,j] < 0 and l[j] = -oo)}.
+*
+* Then (assuming that row lower bound L[p] can be active) the following
+* three cases are possible:
+*
+* 1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
+* in row (1) we can use formulae (15) and (18);
+*
+* 2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
+* so for variable x[k] we can use formulae (8) and (9). Note that
+* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
+* or u'[j] = +oo (if a[p,j] < 0);
+*
+* 3) |J''| > 1. In this case for all variables x[j] in row (1) we have
+* l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
+
+void npp_implied_bounds(NPP *npp, NPPROW *p)
+{ NPPAIJ *apj, *apk;
+ double big, eps, temp;
+ xassert(npp == npp);
+ /* initialize implied bounds for all variables and determine
+ maximal magnitude of row coefficients a[p,j] */
+ big = 1.0;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
+ if (big < fabs(apj->val)) big = fabs(apj->val);
+ }
+ eps = 1e-6 * big;
+ /* process row lower bound (assuming that it can be active) */
+ if (p->lb != -DBL_MAX)
+ { apk = NULL;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
+ apj->val < 0.0 && apj->col->lb == -DBL_MAX)
+ { if (apk == NULL)
+ apk = apj;
+ else
+ goto skip1;
+ }
+ }
+ /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
+ temp = p->lb;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj == apk)
+ /* skip a[p,k] */;
+ else if (apj->val > 0.0)
+ temp -= apj->val * apj->col->ub;
+ else /* apj->val < 0.0 */
+ temp -= apj->val * apj->col->lb;
+ }
+ /* compute column implied bounds */
+ if (apk == NULL)
+ { /* temp = L[p] - U'[p] */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val >= +eps)
+ { /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
+ apj->col->ll.ll = apj->col->ub + temp / apj->val;
+ }
+ else if (apj->val <= -eps)
+ { /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
+ apj->col->uu.uu = apj->col->lb + temp / apj->val;
+ }
+ }
+ }
+ else
+ { /* temp = L[p,k] */
+ if (apk->val >= +eps)
+ { /* l'[k] := L[p,k] / a[p,k] */
+ apk->col->ll.ll = temp / apk->val;
+ }
+ else if (apk->val <= -eps)
+ { /* u'[k] := L[p,k] / a[p,k] */
+ apk->col->uu.uu = temp / apk->val;
+ }
+ }
+skip1: ;
+ }
+ /* process row upper bound (assuming that it can be active) */
+ if (p->ub != +DBL_MAX)
+ { apk = NULL;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
+ apj->val < 0.0 && apj->col->ub == +DBL_MAX)
+ { if (apk == NULL)
+ apk = apj;
+ else
+ goto skip2;
+ }
+ }
+ /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
+ temp = p->ub;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj == apk)
+ /* skip a[p,k] */;
+ else if (apj->val > 0.0)
+ temp -= apj->val * apj->col->lb;
+ else /* apj->val < 0.0 */
+ temp -= apj->val * apj->col->ub;
+ }
+ /* compute column implied bounds */
+ if (apk == NULL)
+ { /* temp = U[p] - L'[p] */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val >= +eps)
+ { /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
+ apj->col->uu.uu = apj->col->lb + temp / apj->val;
+ }
+ else if (apj->val <= -eps)
+ { /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
+ apj->col->ll.ll = apj->col->ub + temp / apj->val;
+ }
+ }
+ }
+ else
+ { /* temp = U[p,k] */
+ if (apk->val >= +eps)
+ { /* u'[k] := U[p,k] / a[p,k] */
+ apk->col->uu.uu = temp / apk->val;
+ }
+ else if (apk->val <= -eps)
+ { /* l'[k] := U[p,k] / a[p,k] */
+ apk->col->ll.ll = temp / apk->val;
+ }
+ }
+skip2: ;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp4.c b/test/monniaux/glpk-4.65/src/npp/npp4.c
new file mode 100644
index 00000000..d7dd0e86
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp4.c
@@ -0,0 +1,1414 @@
+/* npp4.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_binarize_prob - binarize MIP problem
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_binarize_prob(NPP *npp);
+*
+* DESCRIPTION
+*
+* The routine npp_binarize_prob replaces in the original MIP problem
+* every integer variable:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], by an equivalent sum of binary variables.
+*
+* RETURNS
+*
+* The routine returns the number of integer variables for which the
+* transformation failed, because u[q] - l[q] > d_max.
+*
+* PROBLEM TRANSFORMATION
+*
+* If variable x[q] has non-zero lower bound, it is first processed
+* with the routine npp_lbnd_col. Thus, we can assume that:
+*
+* 0 <= x[q] <= u[q]. (2)
+*
+* If u[q] = 1, variable x[q] is already binary, so further processing
+* is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
+* smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
+* Then variable x[q] can be replaced by the following sum:
+*
+* n-1
+* x[q] = sum 2^k x[k], (3)
+* k=0
+*
+* where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
+* following additional inequality constraint must be also included in
+* the transformed problem:
+*
+* n-1
+* sum 2^k x[k] <= u[q]. (4)
+* k=0
+*
+* Note: Assuming that in the transformed problem x[q] becomes binary
+* variable x[0], this transformation causes new n-1 binary variables
+* to appear.
+*
+* Substituting x[q] from (3) to the objective row gives:
+*
+* z = sum c[j] x[j] + c[0] =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c[0] =
+* j!=q
+* n-1
+* = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
+* j!=q k=0
+* n-1
+* = sum c[j] x[j] + sum c[k] x[k] + c[0],
+* j!=q k=0
+*
+* where:
+*
+* c[k] = 2^k c[q], k = 0, ..., n-1. (5)
+*
+* And substituting x[q] from (3) to i-th constraint row i gives:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+* n-1
+* L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i] ==>
+* j!=q k=0
+* n-1
+* L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
+* j!=q k=0
+*
+* where:
+*
+* a[i,k] = 2^k a[i,q], k = 0, ..., n-1. (6)
+*
+* RECOVERING SOLUTION
+*
+* Value of variable x[q] is computed with formula (3). */
+
+struct binarize
+{ int q;
+ /* column reference number for x[q] = x[0] */
+ int j;
+ /* column reference number for x[1]; x[2] has reference number
+ j+1, x[3] - j+2, etc. */
+ int n;
+ /* total number of binary variables, n >= 2 */
+};
+
+static int rcv_binarize_prob(NPP *npp, void *info);
+
+int npp_binarize_prob(NPP *npp)
+{ /* binarize MIP problem */
+ struct binarize *info;
+ NPPROW *row;
+ NPPCOL *col, *bin;
+ NPPAIJ *aij;
+ int u, n, k, temp, nfails, nvars, nbins, nrows;
+ /* new variables will be added to the end of the column list, so
+ we go from the end to beginning of the column list */
+ nfails = nvars = nbins = nrows = 0;
+ for (col = npp->c_tail; col != NULL; col = col->prev)
+ { /* skip continuous variable */
+ if (!col->is_int) continue;
+ /* skip fixed variable */
+ if (col->lb == col->ub) continue;
+ /* skip binary variable */
+ if (col->lb == 0.0 && col->ub == 1.0) continue;
+ /* check if the transformation is applicable */
+ if (col->lb < -1e6 || col->ub > +1e6 ||
+ col->ub - col->lb > 4095.0)
+ { /* unfortunately, not */
+ nfails++;
+ continue;
+ }
+ /* process integer non-binary variable x[q] */
+ nvars++;
+ /* make x[q] non-negative, if its lower bound is non-zero */
+ if (col->lb != 0.0)
+ npp_lbnd_col(npp, col);
+ /* now 0 <= x[q] <= u[q] */
+ xassert(col->lb == 0.0);
+ u = (int)col->ub;
+ xassert(col->ub == (double)u);
+ /* if x[q] is binary, further processing is not needed */
+ if (u == 1) continue;
+ /* determine smallest n such that u <= 2^n - 1 (thus, n is the
+ number of binary variables needed) */
+ n = 2, temp = 4;
+ while (u >= temp)
+ n++, temp += temp;
+ nbins += n;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_binarize_prob, sizeof(struct binarize));
+ info->q = col->j;
+ info->j = 0; /* will be set below */
+ info->n = n;
+ /* if u < 2^n - 1, we need one additional row for (4) */
+ if (u < temp - 1)
+ { row = npp_add_row(npp), nrows++;
+ row->lb = -DBL_MAX, row->ub = u;
+ }
+ else
+ row = NULL;
+ /* in the transformed problem variable x[q] becomes binary
+ variable x[0], so its objective and constraint coefficients
+ are not changed */
+ col->ub = 1.0;
+ /* include x[0] into constraint (4) */
+ if (row != NULL)
+ npp_add_aij(npp, row, col, 1.0);
+ /* add other binary variables x[1], ..., x[n-1] */
+ for (k = 1, temp = 2; k < n; k++, temp += temp)
+ { /* add new binary variable x[k] */
+ bin = npp_add_col(npp);
+ bin->is_int = 1;
+ bin->lb = 0.0, bin->ub = 1.0;
+ bin->coef = (double)temp * col->coef;
+ /* store column reference number for x[1] */
+ if (info->j == 0)
+ info->j = bin->j;
+ else
+ xassert(info->j + (k-1) == bin->j);
+ /* duplicate constraint coefficients for x[k]; this also
+ automatically includes x[k] into constraint (4) */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
+ }
+ }
+ if (nvars > 0)
+ xprintf("%d integer variable(s) were replaced by %d binary one"
+ "s\n", nvars, nbins);
+ if (nrows > 0)
+ xprintf("%d row(s) were added due to binarization\n", nrows);
+ if (nfails > 0)
+ xprintf("Binarization failed for %d integer variable(s)\n",
+ nfails);
+ return nfails;
+}
+
+static int rcv_binarize_prob(NPP *npp, void *_info)
+{ /* recovery binarized variable */
+ struct binarize *info = _info;
+ int k, temp;
+ double sum;
+ /* compute value of x[q]; see formula (3) */
+ sum = npp->c_value[info->q];
+ for (k = 1, temp = 2; k < info->n; k++, temp += temp)
+ sum += (double)temp * npp->c_value[info->j + (k-1)];
+ npp->c_value[info->q] = sum;
+ return 0;
+}
+
+/**********************************************************************/
+
+struct elem
+{ /* linear form element a[j] x[j] */
+ double aj;
+ /* non-zero coefficient value */
+ NPPCOL *xj;
+ /* pointer to variable (column) */
+ struct elem *next;
+ /* pointer to another term */
+};
+
+static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
+{ /* copy linear form */
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ ptr = NULL;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { e = dmp_get_atom(npp->pool, sizeof(struct elem));
+ e->aj = s * aij->val;
+ e->xj = aij->col;
+ e->next = ptr;
+ ptr = e;
+ }
+ return ptr;
+}
+
+static void drop_form(NPP *npp, struct elem *ptr)
+{ /* drop linear form */
+ struct elem *e;
+ while (ptr != NULL)
+ { e = ptr;
+ ptr = e->next;
+ dmp_free_atom(npp->pool, e, sizeof(struct elem));
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_packing - test if constraint is packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_packing(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is packing inequality (see below),
+* the routine npp_is_packing returns non-zero. Otherwise, it returns
+* zero.
+*
+* PACKING INEQUALITIES
+*
+* In canonical format the packing inequality is the following:
+*
+* sum x[j] <= 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This inequality expresses the
+* condition that in any integer feasible solution at most one variable
+* from set J can take non-zero (unity) value while other variables
+* must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
+* if J is empty or |J| = 1, the inequality (1) is redundant.
+*
+* In general case the packing inequality may include original variables
+* x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] <= 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+* sum x[j] - sum x[j] <= 1 - |Jn|. (3)
+* j in Jp j in Jn */
+
+int npp_is_packing(NPP *npp, NPPROW *row)
+{ /* test if constraint is packing inequality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
+ return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->ub != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_hidden_packing - identify hidden packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_hidden_packing(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_hidden_packing processes specified inequality
+* constraint, which includes only binary variables, and the number of
+* the variables is not less than two. If the original inequality is
+* equivalent to a packing inequality, the routine replaces it by this
+* equivalent inequality. If the original constraint is double-sided
+* inequality, it is replaced by a pair of single-sided inequalities,
+* if necessary.
+*
+* RETURNS
+*
+* If the original inequality constraint was replaced by equivalent
+* packing inequality, the routine npp_hidden_packing returns non-zero.
+* Otherwise, it returns zero.
+*
+* PROBLEM TRANSFORMATION
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] <= b, (1)
+* j in J
+*
+* where all variables x[j] are binary, and |J| >= 2. (In case of '>='
+* inequality it can be transformed to '<=' format by multiplying both
+* its sides by -1.)
+*
+* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+* x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+* sum a[j] x[j] <= b ==>
+* j in J
+*
+* sum a[j] x[j] + sum a[j] x[j] <= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] + sum a[j] (1 - x~[j]) <= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] - sum a[j] x~[j] <= b - sum a[j].
+* j in Jp j in Jn j in Jn
+*
+* Thus, meaning the transformation above, we can assume that in
+* inequality (1) all coefficients a[j] are positive. Moreover, we can
+* assume that a[j] <= b. In fact, let a[j] > b; then the following
+* three cases are possible:
+*
+* 1) b < 0. In this case inequality (1) is infeasible, so the problem
+* has no feasible solution (see the routine npp_analyze_row);
+*
+* 2) b = 0. In this case inequality (1) is a forcing inequality on its
+* upper bound (see the routine npp_forcing row), from which it
+* follows that all variables x[j] should be fixed at zero;
+*
+* 3) b > 0. In this case inequality (1) defines an implied zero upper
+* bound for variable x[j] (see the routine npp_implied_bounds), from
+* which it follows that x[j] should be fixed at zero.
+*
+* It is assumed that all three cases listed above have been recognized
+* by the routine npp_process_prob, which performs basic MIP processing
+* prior to a call the routine npp_hidden_packing. So, if one of these
+* cases occurs, we should just skip processing such constraint.
+*
+* Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
+* equivalent to packing inquality only if:
+*
+* a[j] + a[k] > b + eps (2)
+*
+* for all j, k in J, j != k, where eps is an absolute tolerance for
+* row (linear form) value. Checking the condition (2) for all j and k,
+* j != k, requires time O(|J|^2). However, this time can be reduced to
+* O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
+* to check the condition (2) only once.
+*
+* Once the original inequality (1) is replaced by equivalent packing
+* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+* all j in Jn (see above).
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] <= b;
+ 0 - specified row is NOT hidden packing inequality;
+ 1 - specified row is packing inequality;
+ 2 - specified row is hidden packing inequality. */
+ struct elem *e, *ej, *ek;
+ int neg;
+ double b = *_b, eps;
+ xassert(npp == npp);
+ /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+ for (e = ptr; e != NULL; e = e->next)
+ { xassert(e->aj != 0.0);
+ xassert(e->xj->is_int);
+ xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+ }
+ /* check if the specified inequality constraint already has the
+ form of packing inequality */
+ neg = 0; /* neg is |Jn| */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj == +1.0)
+ ;
+ else if (e->aj == -1.0)
+ neg++;
+ else
+ break;
+ }
+ if (e == NULL)
+ { /* all coefficients a[j] are +1 or -1; check rhs b */
+ if (b == (double)(1 - neg))
+ { /* it is packing inequality; no processing is needed */
+ return 1;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+ positive; the result is a~[j] = |a[j]| and new rhs b */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0) b -= e->aj;
+ /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+ /* if a[j] > b, skip processing--this case must not appear */
+ for (e = ptr; e != NULL; e = e->next)
+ if (fabs(e->aj) > b) return 0;
+ /* now 0 < a[j] <= b for all j in J */
+ /* find two minimal coefficients a[j] and a[k], j != k */
+ ej = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
+ xassert(ej != NULL);
+ ek = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ if (e != ej)
+ if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
+ xassert(ek != NULL);
+ /* the specified constraint is equivalent to packing inequality
+ iff a[j] + a[k] > b + eps */
+ eps = 1e-3 + 1e-6 * fabs(b);
+ if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
+ /* perform back substitution x~[j] = 1 - x[j] and construct the
+ final equivalent packing inequality in generalized format */
+ b = 1.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ e->aj = +1.0;
+ else /* e->aj < 0.0 */
+ e->aj = -1.0, b -= 1.0;
+ }
+ *_b = b;
+ return 2;
+}
+
+int npp_hidden_packing(NPP *npp, NPPROW *row)
+{ /* identify hidden packing inequality */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, ret, count = 0;
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->ub;
+ }
+ else
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->lb;
+ }
+ /* now the inequality has the form "sum a[j] x[j] <= b" */
+ ret = hidden_packing(npp, ptr, &b);
+ xassert(0 <= ret && ret <= 2);
+ if (kase == 1 && ret == 1 || ret == 2)
+ { /* the original inequality has been identified as hidden
+ packing inequality */
+ count++;
+#ifdef GLP_DEBUG
+ xprintf("Original constraint:\n");
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ xprintf(" %+g x%d", aij->val, aij->col->j);
+ if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+ if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+ xprintf("\n");
+ xprintf("Equivalent packing inequality:\n");
+ for (e = ptr; e != NULL; e = e->next)
+ xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+ xprintf(", <= %g\n", b);
+#endif
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ else
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = -DBL_MAX, row->ub = b;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing lower bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_packing - identify implied packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+* NPPCOL *var[], char set[]);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_packing processes specified row (constraint)
+* of general format:
+*
+* L <= sum a[j] x[j] <= U. (1)
+* j
+*
+* If which = 0, only lower bound L, which must exist, is considered,
+* while upper bound U is ignored. Similarly, if which = 1, only upper
+* bound U, which must exist, is considered, while lower bound L is
+* ignored. Thus, if the specified row is a double-sided inequality or
+* equality constraint, this routine should be called twice for both
+* lower and upper bounds.
+*
+* The routine npp_implied_packing attempts to find a non-trivial (i.e.
+* having not less than two binary variables) packing inequality:
+*
+* sum x[j] - sum x[j] <= 1 - |Jn|, (2)
+* j in Jp j in Jn
+*
+* which is relaxation of the constraint (1) in the sense that any
+* solution satisfying to that constraint also satisfies to the packing
+* inequality (2). If such relaxation exists, the routine stores
+* pointers to descriptors of corresponding binary variables and their
+* flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
+* set[2], ..., set[len], where set[j] = 0 means that j in Jp and
+* set[j] = 1 means that j in Jn.
+*
+* RETURNS
+*
+* The routine npp_implied_packing returns len, which is the total
+* number of binary variables in the packing inequality found, len >= 2.
+* However, if the relaxation does not exist, the routine returns zero.
+*
+* ALGORITHM
+*
+* If which = 0, the constraint coefficients (1) are multiplied by -1
+* and b is assigned -L; if which = 1, the constraint coefficients (1)
+* are not changed and b is assigned +U. In both cases the specified
+* constraint gets the following format:
+*
+* sum a[j] x[j] <= b. (3)
+* j
+*
+* (Note that (3) is a relaxation of (1), because one of bounds L or U
+* is ignored.)
+*
+* Let J be set of binary variables, Kp be set of non-binary (integer
+* or continuous) variables with a[j] > 0, and Kn be set of non-binary
+* variables with a[j] < 0. Then the inequality (3) can be written as
+* follows:
+*
+* sum a[j] x[j] <= b - sum a[j] x[j] - sum a[j] x[j]. (4)
+* j in J j in Kp j in Kn
+*
+* To get rid of non-binary variables we can replace the inequality (4)
+* by the following relaxed inequality:
+*
+* sum a[j] x[j] <= b~, (5)
+* j in J
+*
+* where:
+*
+* b~ = sup(b - sum a[j] x[j] - sum a[j] x[j]) =
+* j in Kp j in Kn
+*
+* = b - inf sum a[j] x[j] - inf sum a[j] x[j] = (6)
+* j in Kp j in Kn
+*
+* = b - sum a[j] l[j] - sum a[j] u[j].
+* j in Kp j in Kn
+*
+* Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
+* (if j in Kn) of some non-binary variable x[j] does not exist, then
+* formally b = +oo, in which case further analysis is not performed.
+*
+* Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
+* the inequality coefficients in (5) positive, we replace all x[j] in
+* Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
+* j in Bn, that gives:
+*
+* sum a[j] x[j] - sum a[j] x~[j] <= b~ - sum a[j]. (7)
+* j in Bp j in Bn j in Bn
+*
+* This inequality is a relaxation of the original constraint (1), and
+* it is a binary knapsack inequality. Writing it in the standard format
+* we have:
+*
+* sum alfa[j] z[j] <= beta, (8)
+* j in J
+*
+* where:
+* ( + a[j], if j in Bp,
+* alfa[j] = < (9)
+* ( - a[j], if j in Bn,
+*
+* ( x[j], if j in Bp,
+* z[j] = < (10)
+* ( 1 - x[j], if j in Bn,
+*
+* beta = b~ - sum a[j]. (11)
+* j in Bn
+*
+* In the inequality (8) all coefficients are positive, therefore, the
+* packing relaxation to be found for this inequality is the following:
+*
+* sum z[j] <= 1. (12)
+* j in P
+*
+* It is obvious that set P within J, which we would like to find, must
+* satisfy to the following condition:
+*
+* alfa[j] + alfa[k] > beta + eps for all j, k in P, j != k, (13)
+*
+* where eps is an absolute tolerance for value of the linear form.
+* Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
+* Moreover, if in the equality (8) there exist coefficients alfa[k],
+* for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
+* satisfies to the condition (13) for all j in P, *one* corresponding
+* variable z[k] (having, for example, maximal coefficient alfa[k]) can
+* be included in set P, that allows increasing the number of binary
+* variables in (12) by one.
+*
+* Once the set P has been built, for the inequality (12) we need to
+* perform back substitution according to (10) in order to express it
+* through the original binary variables. As the result of such back
+* substitution the relaxed packing inequality get its final format (2),
+* where Jp = J intersect Bp, and Jn = J intersect Bn. */
+
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+ NPPCOL *var[], char set[])
+{ struct elem *ptr, *e, *i, *k;
+ int len = 0;
+ double b, eps;
+ /* build inequality (3) */
+ if (which == 0)
+ { ptr = copy_form(npp, row, -1.0);
+ xassert(row->lb != -DBL_MAX);
+ b = - row->lb;
+ }
+ else if (which == 1)
+ { ptr = copy_form(npp, row, +1.0);
+ xassert(row->ub != +DBL_MAX);
+ b = + row->ub;
+ }
+ /* remove non-binary variables to build relaxed inequality (5);
+ compute its right-hand side b~ with formula (6) */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+ { /* x[j] is non-binary variable */
+ if (e->aj > 0.0)
+ { if (e->xj->lb == -DBL_MAX) goto done;
+ b -= e->aj * e->xj->lb;
+ }
+ else /* e->aj < 0.0 */
+ { if (e->xj->ub == +DBL_MAX) goto done;
+ b -= e->aj * e->xj->ub;
+ }
+ /* a[j] = 0 means that variable x[j] is removed */
+ e->aj = 0.0;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
+ compute its right-hand side beta with formula (11) */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0.0) b -= e->aj;
+ /* if beta is close to zero, the knapsack inequality is either
+ infeasible or forcing inequality; this must never happen, so
+ we skip further analysis */
+ if (b < 1e-3) goto done;
+ /* build set P as well as sets Jp and Jn, and determine x[k] as
+ explained above in comments to the routine */
+ eps = 1e-3 + 1e-6 * b;
+ i = k = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ { /* note that alfa[j] = |a[j]| */
+ if (fabs(e->aj) > 0.5 * (b + eps))
+ { /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
+ set Jp or Jn */
+ var[++len] = e->xj;
+ set[len] = (char)(e->aj > 0.0 ? 0 : 1);
+ /* alfa[i] = min alfa[j] over all j included in set P */
+ if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
+ }
+ else if (fabs(e->aj) >= 1e-3)
+ { /* alfa[k] = max alfa[j] over all j not included in set P;
+ we skip coefficient a[j] if it is close to zero to avoid
+ numerically unreliable results */
+ if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
+ }
+ }
+ /* if alfa[k] satisfies to condition (13) for all j in P, include
+ x[k] in P */
+ if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
+ { var[++len] = k->xj;
+ set[len] = (char)(k->aj > 0.0 ? 0 : 1);
+ }
+ /* trivial packing inequality being redundant must never appear,
+ so we just ignore it */
+ if (len < 2) len = 0;
+done: drop_form(npp, ptr);
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_covering - test if constraint is covering inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_covering(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is covering inequality (see below),
+* the routine npp_is_covering returns non-zero. Otherwise, it returns
+* zero.
+*
+* COVERING INEQUALITIES
+*
+* In canonical format the covering inequality is the following:
+*
+* sum x[j] >= 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This inequality expresses the
+* condition that in any integer feasible solution variables in set J
+* cannot be all equal to zero at the same time, i.e. at least one
+* variable must take non-zero (unity) value. W.l.o.g. it is assumed
+* that |J| >= 2, because if J is empty, the inequality (1) is
+* infeasible, and if |J| = 1, the inequality (1) is a forcing row.
+*
+* In general case the covering inequality may include original
+* variables x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] >= 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+* sum x[j] - sum x[j] >= 1 - |Jn|. (3)
+* j in Jp j in Jn
+*
+* (May note that the inequality (3) cuts off infeasible solutions,
+* where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
+*
+* NOTE: If |J| = 2, the inequality (3) is equivalent to packing
+* inequality (see the routine npp_is_packing). */
+
+int npp_is_covering(NPP *npp, NPPROW *row)
+{ /* test if constraint is covering inequality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
+ return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->lb != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_hidden_covering - identify hidden covering inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_hidden_covering(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_hidden_covering processes specified inequality
+* constraint, which includes only binary variables, and the number of
+* the variables is not less than three. If the original inequality is
+* equivalent to a covering inequality (see below), the routine
+* replaces it by the equivalent inequality. If the original constraint
+* is double-sided inequality, it is replaced by a pair of single-sided
+* inequalities, if necessary.
+*
+* RETURNS
+*
+* If the original inequality constraint was replaced by equivalent
+* covering inequality, the routine npp_hidden_covering returns
+* non-zero. Otherwise, it returns zero.
+*
+* PROBLEM TRANSFORMATION
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] >= b, (1)
+* j in J
+*
+* where all variables x[j] are binary, and |J| >= 3. (In case of '<='
+* inequality it can be transformed to '>=' format by multiplying both
+* its sides by -1.)
+*
+* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+* x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+* sum a[j] x[j] >= b ==>
+* j in J
+*
+* sum a[j] x[j] + sum a[j] x[j] >= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] + sum a[j] (1 - x~[j]) >= b ==>
+* j in Jp j in Jn
+*
+* sum m a[j] x[j] - sum a[j] x~[j] >= b - sum a[j].
+* j in Jp j in Jn j in Jn
+*
+* Thus, meaning the transformation above, we can assume that in
+* inequality (1) all coefficients a[j] are positive. Moreover, we can
+* assume that b > 0, because otherwise the inequality (1) would be
+* redundant (see the routine npp_analyze_row). It is then obvious that
+* constraint (1) is equivalent to covering inequality only if:
+*
+* a[j] >= b, (2)
+*
+* for all j in J.
+*
+* Once the original inequality (1) is replaced by equivalent covering
+* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+* all j in Jn (see above).
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] >= b;
+ 0 - specified row is NOT hidden covering inequality;
+ 1 - specified row is covering inequality;
+ 2 - specified row is hidden covering inequality. */
+ struct elem *e;
+ int neg;
+ double b = *_b, eps;
+ xassert(npp == npp);
+ /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+ for (e = ptr; e != NULL; e = e->next)
+ { xassert(e->aj != 0.0);
+ xassert(e->xj->is_int);
+ xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+ }
+ /* check if the specified inequality constraint already has the
+ form of covering inequality */
+ neg = 0; /* neg is |Jn| */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj == +1.0)
+ ;
+ else if (e->aj == -1.0)
+ neg++;
+ else
+ break;
+ }
+ if (e == NULL)
+ { /* all coefficients a[j] are +1 or -1; check rhs b */
+ if (b == (double)(1 - neg))
+ { /* it is covering inequality; no processing is needed */
+ return 1;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+ positive; the result is a~[j] = |a[j]| and new rhs b */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0) b -= e->aj;
+ /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+ /* if b <= 0, skip processing--this case must not appear */
+ if (b < 1e-3) return 0;
+ /* now a[j] > 0 for all j in J, and b > 0 */
+ /* the specified constraint is equivalent to covering inequality
+ iff a[j] >= b for all j in J */
+ eps = 1e-9 + 1e-12 * fabs(b);
+ for (e = ptr; e != NULL; e = e->next)
+ if (fabs(e->aj) < b - eps) return 0;
+ /* perform back substitution x~[j] = 1 - x[j] and construct the
+ final equivalent covering inequality in generalized format */
+ b = 1.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ e->aj = +1.0;
+ else /* e->aj < 0.0 */
+ e->aj = -1.0, b -= 1.0;
+ }
+ *_b = b;
+ return 2;
+}
+
+int npp_hidden_covering(NPP *npp, NPPROW *row)
+{ /* identify hidden covering inequality */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, ret, count = 0;
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->lb;
+ }
+ else
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->ub;
+ }
+ /* now the inequality has the form "sum a[j] x[j] >= b" */
+ ret = hidden_covering(npp, ptr, &b);
+ xassert(0 <= ret && ret <= 2);
+ if (kase == 1 && ret == 1 || ret == 2)
+ { /* the original inequality has been identified as hidden
+ covering inequality */
+ count++;
+#ifdef GLP_DEBUG
+ xprintf("Original constraint:\n");
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ xprintf(" %+g x%d", aij->val, aij->col->j);
+ if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+ if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+ xprintf("\n");
+ xprintf("Equivalent covering inequality:\n");
+ for (e = ptr; e != NULL; e = e->next)
+ xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+ xprintf(", >= %g\n", b);
+#endif
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ else
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = b, row->ub = +DBL_MAX;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing upper bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_partitioning - test if constraint is partitioning equality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_partitioning(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is partitioning equality (see
+* below), the routine npp_is_partitioning returns non-zero. Otherwise,
+* it returns zero.
+*
+* PARTITIONING EQUALITIES
+*
+* In canonical format the partitioning equality is the following:
+*
+* sum x[j] = 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This equality expresses the
+* condition that in any integer feasible solution exactly one variable
+* in set J must take non-zero (unity) value while other variables must
+* be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
+* J is empty, the inequality (1) is infeasible, and if |J| = 1, the
+* inequality (1) is a fixing row.
+*
+* In general case the partitioning equality may include original
+* variables x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] = 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] leads to the partitioning equality in generalized
+* format:
+*
+* sum x[j] - sum x[j] = 1 - |Jn|. (3)
+* j in Jp j in Jn */
+
+int npp_is_partitioning(NPP *npp, NPPROW *row)
+{ /* test if constraint is partitioning equality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (row->lb != row->ub) return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->lb != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_reduce_ineq_coef - reduce inequality constraint coefficients
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_reduce_ineq_coef processes specified inequality
+* constraint attempting to replace it by an equivalent constraint,
+* where magnitude of coefficients at binary variables is smaller than
+* in the original constraint. If the inequality is double-sided, it is
+* replaced by a pair of single-sided inequalities, if necessary.
+*
+* RETURNS
+*
+* The routine npp_reduce_ineq_coef returns the number of coefficients
+* reduced.
+*
+* BACKGROUND
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] >= b. (1)
+* j in J
+*
+* (In case of '<=' inequality it can be transformed to '>=' format by
+* multiplying both its sides by -1.) Let x[k] be a binary variable;
+* other variables can be integer as well as continuous. We can write
+* constraint (1) as follows:
+*
+* a[k] x[k] + t[k] >= b, (2)
+*
+* where:
+*
+* t[k] = sum a[j] x[j]. (3)
+* j in J\{k}
+*
+* Since x[k] is binary, constraint (2) is equivalent to disjunction of
+* the following two constraints:
+*
+* x[k] = 0, t[k] >= b (4)
+*
+* OR
+*
+* x[k] = 1, t[k] >= b - a[k]. (5)
+*
+* Let also that for the partial sum t[k] be known some its implied
+* lower bound inf t[k].
+*
+* Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
+* (4) and (5) and therefore constraint (2) are redundant.
+* If inf t[k] > b - a[k], only constraint (5) is redundant, in which
+* case it can be replaced with the following redundant and therefore
+* equivalent constraint:
+*
+* t[k] >= b - a'[k] = inf t[k], (6)
+*
+* where:
+*
+* a'[k] = b - inf t[k]. (7)
+*
+* Thus, the original constraint (2) is equivalent to the following
+* constraint with coefficient at variable x[k] changed:
+*
+* a'[k] x[k] + t[k] >= b. (8)
+*
+* From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
+* at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
+* a'[k] < a[k], i.e. the coefficient reduces in magnitude.
+*
+* Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
+* constraints (4) and (5) and therefore constraint (2) are redundant.
+* If inf t[k] > b, only constraint (4) is redundant, in which case it
+* can be replaced with the following redundant and therefore equivalent
+* constraint:
+*
+* t[k] >= b' = inf t[k]. (9)
+*
+* Rewriting constraint (5) as follows:
+*
+* t[k] >= b - a[k] = b' - a'[k], (10)
+*
+* where:
+*
+* a'[k] = a[k] + b' - b = a[k] + inf t[k] - b, (11)
+*
+* we can see that disjunction of constraint (9) and (10) is equivalent
+* to disjunction of constraint (4) and (5), from which it follows that
+* the original constraint (2) is equivalent to the following constraint
+* with both coefficient at variable x[k] and right-hand side changed:
+*
+* a'[k] x[k] + t[k] >= b'. (12)
+*
+* From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
+* coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
+* that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
+*
+* PROBLEM TRANSFORMATION
+*
+* In the routine npp_reduce_ineq_coef the following implied lower
+* bound of the partial sum (3) is used:
+*
+* inf t[k] = sum a[j] l[j] + sum a[j] u[j], (13)
+* j in Jp\{k} k in Jn\{k}
+*
+* where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
+* lower and upper bounds, resp., of variable x[j].
+*
+* In order to compute inf t[k] more efficiently, the following formula,
+* which is equivalent to (13), is actually used:
+*
+* ( h - a[k] l[k] = h, if a[k] > 0,
+* inf t[k] = < (14)
+* ( h - a[k] u[k] = h - a[k], if a[k] < 0,
+*
+* where:
+*
+* h = sum a[j] l[j] + sum a[j] u[j] (15)
+* j in Jp j in Jn
+*
+* is the implied lower bound of row (1).
+*
+* Reduction of positive coefficient (a[k] > 0) does not change value
+* of h, since l[k] = 0. In case of reduction of negative coefficient
+* (a[k] < 0) from (11) it follows that:
+*
+* delta a[k] = a'[k] - a[k] = inf t[k] - b (> 0), (16)
+*
+* so new value of h (accounting that u[k] = 1) can be computed as
+* follows:
+*
+* h := h + delta a[k] = h + (inf t[k] - b). (17)
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] >= b */
+ /* returns: the number of coefficients reduced */
+ struct elem *e;
+ int count = 0;
+ double h, inf_t, new_a, b = *_b;
+ xassert(npp == npp);
+ /* compute h; see (15) */
+ h = 0.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ { if (e->xj->lb == -DBL_MAX) goto done;
+ h += e->aj * e->xj->lb;
+ }
+ else /* e->aj < 0.0 */
+ { if (e->xj->ub == +DBL_MAX) goto done;
+ h += e->aj * e->xj->ub;
+ }
+ }
+ /* perform reduction of coefficients at binary variables */
+ for (e = ptr; e != NULL; e = e->next)
+ { /* skip non-binary variable */
+ if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+ continue;
+ if (e->aj > 0.0)
+ { /* compute inf t[k]; see (14) */
+ inf_t = h;
+ if (b - e->aj < inf_t && inf_t < b)
+ { /* compute reduced coefficient a'[k]; see (7) */
+ new_a = b - inf_t;
+ if (new_a >= +1e-3 &&
+ e->aj - new_a >= 0.01 * (1.0 + e->aj))
+ { /* accept a'[k] */
+#ifdef GLP_DEBUG
+ xprintf("+");
+#endif
+ e->aj = new_a;
+ count++;
+ }
+ }
+ }
+ else /* e->aj < 0.0 */
+ { /* compute inf t[k]; see (14) */
+ inf_t = h - e->aj;
+ if (b < inf_t && inf_t < b - e->aj)
+ { /* compute reduced coefficient a'[k]; see (11) */
+ new_a = e->aj + (inf_t - b);
+ if (new_a <= -1e-3 &&
+ new_a - e->aj >= 0.01 * (1.0 - e->aj))
+ { /* accept a'[k] */
+#ifdef GLP_DEBUG
+ xprintf("-");
+#endif
+ e->aj = new_a;
+ /* update h; see (17) */
+ h += (inf_t - b);
+ /* compute b'; see (9) */
+ b = inf_t;
+ count++;
+ }
+ }
+ }
+ }
+ *_b = b;
+done: return count;
+}
+
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
+{ /* reduce inequality constraint coefficients */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, count[2];
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ count[0] = count[1] = 0;
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+#ifdef GLP_DEBUG
+ xprintf("L");
+#endif
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->lb;
+ }
+ else
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+#ifdef GLP_DEBUG
+ xprintf("U");
+#endif
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->ub;
+ }
+ /* now the inequality has the form "sum a[j] x[j] >= b" */
+ count[kase] = reduce_ineq_coef(npp, ptr, &b);
+ if (count[kase] > 0)
+ { /* the original inequality has been replaced by equivalent
+ one with coefficients reduced */
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+#ifdef GLP_DEBUG
+ xprintf("*");
+#endif
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ else
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = b, row->ub = +DBL_MAX;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing upper bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count[0] + count[1];
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp5.c b/test/monniaux/glpk-4.65/src/npp/npp5.c
new file mode 100644
index 00000000..2fad496d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp5.c
@@ -0,0 +1,809 @@
+/* npp5.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_clean_prob - perform initial LP/MIP processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_clean_prob(NPP *npp);
+*
+* DESCRIPTION
+*
+* The routine npp_clean_prob performs initial LP/MIP processing that
+* currently includes:
+*
+* 1) removing free rows;
+*
+* 2) replacing double-sided constraint rows with almost identical
+* bounds, by equality constraint rows;
+*
+* 3) removing fixed columns;
+*
+* 4) replacing double-bounded columns with almost identical bounds by
+* fixed columns and removing those columns;
+*
+* 5) initial processing constraint coefficients (not implemented);
+*
+* 6) initial processing objective coefficients (not implemented). */
+
+void npp_clean_prob(NPP *npp)
+{ /* perform initial LP/MIP processing */
+ NPPROW *row, *next_row;
+ NPPCOL *col, *next_col;
+ int ret;
+ xassert(npp == npp);
+ /* process rows which originally are free */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* process free row */
+#ifdef GLP_DEBUG
+ xprintf("1");
+#endif
+ npp_free_row(npp, row);
+ /* row was deleted */
+ }
+ }
+ /* process rows which originally are double-sided inequalities */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
+ row->lb < row->ub)
+ { ret = npp_make_equality(npp, row);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ { /* row was replaced by equality constraint */
+#ifdef GLP_DEBUG
+ xprintf("2");
+#endif
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+ /* process columns which are originally fixed */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb == col->ub)
+ { /* process fixed column */
+#ifdef GLP_DEBUG
+ xprintf("3");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ }
+ /* process columns which are originally double-bounded */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
+ col->lb < col->ub)
+ { ret = npp_make_fixed(npp, col);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ { /* column was replaced by fixed column; process it */
+#ifdef GLP_DEBUG
+ xprintf("4");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_row - perform basic row processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_row(NPP *npp, NPPROW *row, int hard);
+*
+* DESCRIPTION
+*
+* The routine npp_process_row performs basic row processing that
+* currently includes:
+*
+* 1) removing empty row;
+*
+* 2) removing equality constraint row singleton and corresponding
+* column;
+*
+* 3) removing inequality constraint row singleton and corresponding
+* column if it was fixed;
+*
+* 4) performing general row analysis;
+*
+* 5) removing redundant row bounds;
+*
+* 6) removing forcing row and corresponding columns;
+*
+* 7) removing row which becomes free due to redundant bounds;
+*
+* 8) computing implied bounds for all columns in the row and using
+* them to strengthen current column bounds (MIP only, optional,
+* performed if the flag hard is on).
+*
+* Additionally the routine may activate affected rows and/or columns
+* for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_row(NPP *npp, NPPROW *row, int hard)
+{ /* perform basic row processing */
+ NPPCOL *col;
+ NPPAIJ *aij, *next_aij, *aaa;
+ int ret;
+ /* row must not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* start processing row */
+ if (row->ptr == NULL)
+ { /* empty row */
+ ret = npp_empty_row(npp, row);
+ if (ret == 0)
+ { /* row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("A");
+#endif
+ return 0;
+ }
+ else if (ret == 1)
+ { /* primal infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ if (row->ptr->r_next == NULL)
+ { /* row singleton */
+ col = row->ptr->col;
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ ret = npp_eq_singlet(npp, row);
+ if (ret == 0)
+ { /* column was fixed, row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("B");
+#endif
+ /* activate rows affected by column */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_activate_row(npp, aij->row);
+ /* process fixed column */
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ return 0;
+ }
+ else if (ret == 1 || ret == 2)
+ { /* primal/integer infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ else
+ { /* inequality constraint */
+ ret = npp_ineq_singlet(npp, row);
+ if (0 <= ret && ret <= 3)
+ { /* row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("C");
+#endif
+ /* activate column, since its length was changed due to
+ row deletion */
+ npp_activate_col(npp, col);
+ if (ret >= 2)
+ { /* column bounds changed significantly or column was
+ fixed */
+ /* activate rows affected by column */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_activate_row(npp, aij->row);
+ }
+ if (ret == 3)
+ { /* column was fixed; process it */
+#ifdef GLP_DEBUG
+ xprintf("D");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ return 0;
+ }
+ else if (ret == 4)
+ { /* primal infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+#if 0
+ /* sometimes this causes too large round-off errors; probably
+ pivot coefficient should be chosen more carefully */
+ if (row->ptr->r_next->r_next == NULL)
+ { /* row doubleton */
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ if (!(row->ptr->col->is_int ||
+ row->ptr->r_next->col->is_int))
+ { /* both columns are continuous */
+ NPPCOL *q;
+ q = npp_eq_doublet(npp, row);
+ if (q != NULL)
+ { /* column q was eliminated */
+#ifdef GLP_DEBUG
+ xprintf("E");
+#endif
+ /* now column q is singleton of type "implied slack
+ variable"; we process it here to make sure that on
+ recovering basic solution the row is always active
+ equality constraint (as required by the routine
+ rcv_eq_doublet) */
+ xassert(npp_process_col(npp, q) == 0);
+ /* column q was deleted; note that row p also may be
+ deleted */
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+ /* general row analysis */
+ ret = npp_analyze_row(npp, row);
+ xassert(0x00 <= ret && ret <= 0xFF);
+ if (ret == 0x33)
+ { /* row bounds are inconsistent with column bounds */
+ return GLP_ENOPFS;
+ }
+ if ((ret & 0x0F) == 0x00)
+ { /* row lower bound does not exist or redundant */
+ if (row->lb != -DBL_MAX)
+ { /* remove redundant row lower bound */
+#ifdef GLP_DEBUG
+ xprintf("F");
+#endif
+ npp_inactive_bound(npp, row, 0);
+ }
+ }
+ else if ((ret & 0x0F) == 0x01)
+ { /* row lower bound can be active */
+ /* see below */
+ }
+ else if ((ret & 0x0F) == 0x02)
+ { /* row lower bound is a forcing bound */
+#ifdef GLP_DEBUG
+ xprintf("G");
+#endif
+ /* process forcing row */
+ if (npp_forcing_row(npp, row, 0) == 0)
+fixup: { /* columns were fixed, row was made free */
+ for (aij = row->ptr; aij != NULL; aij = next_aij)
+ { /* process column fixed by forcing row */
+#ifdef GLP_DEBUG
+ xprintf("H");
+#endif
+ col = aij->col;
+ next_aij = aij->r_next;
+ /* activate rows affected by column */
+ for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_activate_row(npp, aaa->row);
+ /* process fixed column */
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ /* process free row (which now is empty due to deletion of
+ all its columns) */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ return 0;
+ }
+ }
+ else
+ xassert(ret != ret);
+ if ((ret & 0xF0) == 0x00)
+ { /* row upper bound does not exist or redundant */
+ if (row->ub != +DBL_MAX)
+ { /* remove redundant row upper bound */
+#ifdef GLP_DEBUG
+ xprintf("I");
+#endif
+ npp_inactive_bound(npp, row, 1);
+ }
+ }
+ else if ((ret & 0xF0) == 0x10)
+ { /* row upper bound can be active */
+ /* see below */
+ }
+ else if ((ret & 0xF0) == 0x20)
+ { /* row upper bound is a forcing bound */
+#ifdef GLP_DEBUG
+ xprintf("J");
+#endif
+ /* process forcing row */
+ if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
+ }
+ else
+ xassert(ret != ret);
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row became free due to redundant bounds removal */
+#ifdef GLP_DEBUG
+ xprintf("K");
+#endif
+ /* activate its columns, since their length will change due
+ to row deletion */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_activate_col(npp, aij->col);
+ /* process free row */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ return 0;
+ }
+#if 1 /* 23/XII-2009 */
+ /* row lower and/or upper bounds can be active */
+ if (npp->sol == GLP_MIP && hard)
+ { /* improve current column bounds (optional) */
+ if (npp_improve_bounds(npp, row, 1) < 0)
+ return GLP_ENOPFS;
+ }
+#endif
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_improve_bounds - improve current column bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+*
+* DESCRIPTION
+*
+* The routine npp_improve_bounds analyzes specified row (inequality
+* or equality constraint) to determine implied column bounds and then
+* uses these bounds to improve (strengthen) current column bounds.
+*
+* If the flag is on and current column bounds changed significantly
+* or the column was fixed, the routine activate rows affected by the
+* column for further processing. (This feature is intended to be used
+* in the main loop of the routine npp_process_row.)
+*
+* NOTE: This operation can be used for MIP problem only.
+*
+* RETURNS
+*
+* The routine npp_improve_bounds returns the number of significantly
+* changed bounds plus the number of column having been fixed due to
+* bound improvements. However, if the routine detects primal/integer
+* infeasibility, it returns a negative value. */
+
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
+{ /* improve current column bounds */
+ NPPCOL *col;
+ NPPAIJ *aij, *next_aij, *aaa;
+ int kase, ret, count = 0;
+ double lb, ub;
+ xassert(npp->sol == GLP_MIP);
+ /* row must not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* determine implied column bounds */
+ npp_implied_bounds(npp, row);
+ /* and use these bounds to strengthen current column bounds */
+ for (aij = row->ptr; aij != NULL; aij = next_aij)
+ { col = aij->col;
+ next_aij = aij->r_next;
+ for (kase = 0; kase <= 1; kase++)
+ { /* save current column bounds */
+ lb = col->lb, ub = col->ub;
+ if (kase == 0)
+ { /* process implied column lower bound */
+ if (col->ll.ll == -DBL_MAX) continue;
+ ret = npp_implied_lower(npp, col, col->ll.ll);
+ }
+ else
+ { /* process implied column upper bound */
+ if (col->uu.uu == +DBL_MAX) continue;
+ ret = npp_implied_upper(npp, col, col->uu.uu);
+ }
+ if (ret == 0 || ret == 1)
+ { /* current column bounds did not change or changed, but
+ not significantly; restore current column bounds */
+ col->lb = lb, col->ub = ub;
+ }
+ else if (ret == 2 || ret == 3)
+ { /* current column bounds changed significantly or column
+ was fixed */
+#ifdef GLP_DEBUG
+ xprintf("L");
+#endif
+ count++;
+ /* activate other rows affected by column, if required */
+ if (flag)
+ { for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+ { if (aaa->row != row)
+ npp_activate_row(npp, aaa->row);
+ }
+ }
+ if (ret == 3)
+ { /* process fixed column */
+#ifdef GLP_DEBUG
+ xprintf("M");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ break; /* for kase */
+ }
+ }
+ else if (ret == 4)
+ { /* primal/integer infeasibility */
+ return -1;
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_col - perform basic column processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_col(NPP *npp, NPPCOL *col);
+*
+* DESCRIPTION
+*
+* The routine npp_process_col performs basic column processing that
+* currently includes:
+*
+* 1) fixing and removing empty column;
+*
+* 2) removing column singleton, which is implied slack variable, and
+* corresponding row if it becomes free;
+*
+* 3) removing bounds of column, which is implied free variable, and
+* replacing corresponding row by equality constraint.
+*
+* Additionally the routine may activate affected rows and/or columns
+* for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_col(NPP *npp, NPPCOL *col)
+{ /* perform basic column processing */
+ NPPROW *row;
+ NPPAIJ *aij;
+ int ret;
+ /* column must not be fixed */
+ xassert(col->lb < col->ub);
+ /* start processing column */
+ if (col->ptr == NULL)
+ { /* empty column */
+ ret = npp_empty_col(npp, col);
+ if (ret == 0)
+ { /* column was fixed and deleted */
+#ifdef GLP_DEBUG
+ xprintf("N");
+#endif
+ return 0;
+ }
+ else if (ret == 1)
+ { /* dual infeasibility */
+ return GLP_ENODFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ if (col->ptr->c_next == NULL)
+ { /* column singleton */
+ row = col->ptr->row;
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ if (!col->is_int)
+slack: { /* implied slack variable */
+#ifdef GLP_DEBUG
+ xprintf("O");
+#endif
+ npp_implied_slack(npp, col);
+ /* column was deleted */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row became free due to implied slack variable */
+#ifdef GLP_DEBUG
+ xprintf("P");
+#endif
+ /* activate columns affected by row */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_activate_col(npp, aij->col);
+ /* process free row */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ }
+ else
+ { /* row became inequality constraint; activate it
+ since its length changed due to column deletion */
+ npp_activate_row(npp, row);
+ }
+ return 0;
+ }
+ }
+ else
+ { /* inequality constraint */
+ if (!col->is_int)
+ { ret = npp_implied_free(npp, col);
+ if (ret == 0)
+ { /* implied free variable */
+#ifdef GLP_DEBUG
+ xprintf("Q");
+#endif
+ /* column bounds were removed, row was replaced by
+ equality constraint */
+ goto slack;
+ }
+ else if (ret == 1)
+ { /* column is not implied free variable, because its
+ lower and/or upper bounds can be active */
+ }
+ else if (ret == 2)
+ { /* dual infeasibility */
+ return GLP_ENODFS;
+ }
+ }
+ }
+ }
+ /* column still exists */
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_prob - perform basic LP/MIP processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_prob(NPP *npp, int hard);
+*
+* DESCRIPTION
+*
+* The routine npp_process_prob performs basic LP/MIP processing that
+* currently includes:
+*
+* 1) initial LP/MIP processing (see the routine npp_clean_prob),
+*
+* 2) basic row processing (see the routine npp_process_row), and
+*
+* 3) basic column processing (see the routine npp_process_col).
+*
+* If the flag hard is on, the routine attempts to improve current
+* column bounds multiple times within the main processing loop, in
+* which case this feature may take a time. Otherwise, if the flag hard
+* is off, improving column bounds is performed only once at the end of
+* the main loop. (Note that this feature is used for MIP only.)
+*
+* The routine uses two sets: the set of active rows and the set of
+* active columns. Rows/columns are marked by a flag (the field temp in
+* NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
+* in which case it is placed in the beginning of the row/column list;
+* otherwise, if the flag is zero, the row/column is inactive, in which
+* case it is placed in the end of the row/column list. If a row/column
+* being currently processed may affect other rows/columns, the latters
+* are activated for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_prob(NPP *npp, int hard)
+{ /* perform basic LP/MIP processing */
+ NPPROW *row;
+ NPPCOL *col;
+ int processing, ret;
+ /* perform initial LP/MIP processing */
+ npp_clean_prob(npp);
+ /* activate all remaining rows and columns */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ row->temp = 1;
+ for (col = npp->c_head; col != NULL; col = col->next)
+ col->temp = 1;
+ /* main processing loop */
+ processing = 1;
+ while (processing)
+ { processing = 0;
+ /* process all active rows */
+ for (;;)
+ { row = npp->r_head;
+ if (row == NULL || !row->temp) break;
+ npp_deactivate_row(npp, row);
+ ret = npp_process_row(npp, row, hard);
+ if (ret != 0) goto done;
+ processing = 1;
+ }
+ /* process all active columns */
+ for (;;)
+ { col = npp->c_head;
+ if (col == NULL || !col->temp) break;
+ npp_deactivate_col(npp, col);
+ ret = npp_process_col(npp, col);
+ if (ret != 0) goto done;
+ processing = 1;
+ }
+ }
+#if 1 /* 23/XII-2009 */
+ if (npp->sol == GLP_MIP && !hard)
+ { /* improve current column bounds (optional) */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ { if (npp_improve_bounds(npp, row, 0) < 0)
+ { ret = GLP_ENOPFS;
+ goto done;
+ }
+ }
+ }
+#endif
+ /* all seems ok */
+ ret = 0;
+done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
+#ifdef GLP_DEBUG
+ xprintf("\n");
+#endif
+ return ret;
+}
+
+/**********************************************************************/
+
+int npp_simplex(NPP *npp, const glp_smcp *parm)
+{ /* process LP prior to applying primal/dual simplex method */
+ int ret;
+ xassert(npp->sol == GLP_SOL);
+ xassert(parm == parm);
+ ret = npp_process_prob(npp, 0);
+ return ret;
+}
+
+/**********************************************************************/
+
+int npp_integer(NPP *npp, const glp_iocp *parm)
+{ /* process MIP prior to applying branch-and-bound method */
+ NPPROW *row, *prev_row;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int count, ret;
+ xassert(npp->sol == GLP_MIP);
+ xassert(parm == parm);
+ /*==============================================================*/
+ /* perform basic MIP processing */
+ ret = npp_process_prob(npp, 1);
+ if (ret != 0) goto done;
+ /*==============================================================*/
+ /* binarize problem, if required */
+ if (parm->binarize)
+ npp_binarize_prob(npp);
+ /*==============================================================*/
+ /* identify hidden packing inequalities */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip free row */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ /* skip row having less than two variables */
+ if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
+ /* skip row having non-binary variables */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ break;
+ }
+ if (aij != NULL) continue;
+ count += npp_hidden_packing(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d hidden packing inequaliti(es) were detected\n",
+ count);
+ /*==============================================================*/
+ /* identify hidden covering inequalities */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip free row */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ /* skip row having less than three variables */
+ if (row->ptr == NULL || row->ptr->r_next == NULL ||
+ row->ptr->r_next->r_next == NULL) continue;
+ /* skip row having non-binary variables */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ break;
+ }
+ if (aij != NULL) continue;
+ count += npp_hidden_covering(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d hidden covering inequaliti(es) were detected\n",
+ count);
+ /*==============================================================*/
+ /* reduce inequality constraint coefficients */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ count += npp_reduce_ineq_coef(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d constraint coefficient(s) were reduced\n", count);
+ /*==============================================================*/
+#ifdef GLP_DEBUG
+ routine(npp);
+#endif
+ /*==============================================================*/
+ /* all seems ok */
+ ret = 0;
+done: return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp6.c b/test/monniaux/glpk-4.65/src/npp/npp6.c
new file mode 100644
index 00000000..b57f8615
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp6.c
@@ -0,0 +1,1500 @@
+/* npp6.c (translate feasibility problem to CNF-SAT) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2011-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* npp_sat_free_row - process free (unbounded) row
+*
+* This routine processes row p, which is free (i.e. has no finite
+* bounds):
+*
+* -inf < sum a[p,j] x[j] < +inf. (1)
+*
+* The constraint (1) cannot be active and therefore it is redundant,
+* so the routine simply removes it from the original problem. */
+
+void npp_sat_free_row(NPP *npp, NPPROW *p)
+{ /* the row should be free */
+ xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return;
+}
+
+/***********************************************************************
+* npp_sat_fixed_col - process fixed column
+*
+* This routine processes column q, which is fixed:
+*
+* x[q] = s[q], (1)
+*
+* where s[q] is a fixed column value.
+*
+* The routine substitutes fixed value s[q] into constraint rows and
+* then removes column x[q] from the original problem.
+*
+* Substitution of x[q] = s[q] into row i gives:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] s[q], (2)
+*
+* U~[i] = U[i] - a[i,q] s[q] (3)
+*
+* are, respectively, lower and upper bound of row i in the transformed
+* problem.
+*
+* On recovering solution x[q] is assigned the value of s[q]. */
+
+struct sat_fixed_col
+{ /* fixed column */
+ int q;
+ /* column reference number for variable x[q] */
+ int s;
+ /* value, at which x[q] is fixed */
+};
+
+static int rcv_sat_fixed_col(NPP *, void *);
+
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q)
+{ struct sat_fixed_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ int temp;
+ /* the column should be fixed */
+ xassert(q->lb == q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_sat_fixed_col, sizeof(struct sat_fixed_col));
+ info->q = q->j;
+ info->s = (int)q->lb;
+ xassert((double)info->s == q->lb);
+ /* substitute x[q] = s[q] into constraint rows */
+ if (info->s == 0)
+ goto skip;
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb != -DBL_MAX)
+ { i->lb -= aij->val * (double)info->s;
+ temp = (int)i->lb;
+ if ((double)temp != i->lb)
+ return 1; /* integer arithmetic error */
+ }
+ if (i->ub != +DBL_MAX)
+ { i->ub -= aij->val * (double)info->s;
+ temp = (int)i->ub;
+ if ((double)temp != i->ub)
+ return 2; /* integer arithmetic error */
+ }
+ }
+skip: /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return 0;
+}
+
+static int rcv_sat_fixed_col(NPP *npp, void *info_)
+{ struct sat_fixed_col *info = info_;
+ npp->c_value[info->q] = (double)info->s;
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_bin_comb - test if row is binary combination
+*
+* This routine tests if the specified row is a binary combination,
+* i.e. all its constraint coefficients are +1 and -1 and all variables
+* are binary. If the test was passed, the routine returns non-zero,
+* otherwise zero. */
+
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row)
+{ NPPCOL *col;
+ NPPAIJ *aij;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (!(aij->val == +1.0 || aij->val == -1.0))
+ return 0; /* non-unity coefficient */
+ col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0; /* non-binary column */
+ }
+ return 1; /* test was passed */
+}
+
+/***********************************************************************
+* npp_sat_num_pos_coef - determine number of positive coefficients
+*
+* This routine returns the number of positive coefficients in the
+* specified row. */
+
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int num = 0;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ num++;
+ }
+ return num;
+}
+
+/***********************************************************************
+* npp_sat_num_neg_coef - determine number of negative coefficients
+*
+* This routine returns the number of negative coefficients in the
+* specified row. */
+
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int num = 0;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val < 0.0)
+ num++;
+ }
+ return num;
+}
+
+/***********************************************************************
+* npp_sat_is_cover_ineq - test if row is covering inequality
+*
+* The canonical form of a covering inequality is the following:
+*
+* sum x[j] >= 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a covering inequality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] >= 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] <= |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the inequality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the inequality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a covering inequality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row is inequality of '>=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ }
+ }
+ else if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+ { /* row is inequality of '<=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a covering inequality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_pack_ineq - test if row is packing inequality
+*
+* The canonical form of a packing inequality is the following:
+*
+* sum x[j] <= 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a packing inequality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] <= 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] >= |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the inequality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the inequality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a packing inequality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+ { /* row is inequality of '<=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->ub == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ }
+ }
+ else if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row is inequality of '>=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a packing inequality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_partn_eq - test if row is partitioning equality
+*
+* The canonical form of a partitioning equality is the following:
+*
+* sum x[j] = 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a partitioning equality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] = 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] = |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the equality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the equality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a partitioning equality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb == row->ub)
+ { /* row is equality constraint */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a partitioning equality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_reverse_row - multiply both sides of row by -1
+*
+* This routines multiplies by -1 both left- and right-hand sides of
+* the specified row:
+*
+* L <= sum x[j] <= U,
+*
+* that results in the following row:
+*
+* -U <= sum (-x[j]) <= -L.
+*
+* If no integer overflow occured, the routine returns zero, otherwise
+* non-zero. */
+
+int npp_sat_reverse_row(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int temp, ret = 0;
+ double old_lb, old_ub;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { aij->val = -aij->val;
+ temp = (int)aij->val;
+ if ((double)temp != aij->val)
+ ret = 1;
+ }
+ old_lb = row->lb, old_ub = row->ub;
+ if (old_ub == +DBL_MAX)
+ row->lb = -DBL_MAX;
+ else
+ { row->lb = -old_ub;
+ temp = (int)row->lb;
+ if ((double)temp != row->lb)
+ ret = 2;
+ }
+ if (old_lb == -DBL_MAX)
+ row->ub = +DBL_MAX;
+ else
+ { row->ub = -old_lb;
+ temp = (int)row->ub;
+ if ((double)temp != row->ub)
+ ret = 3;
+ }
+ return ret;
+}
+
+/***********************************************************************
+* npp_sat_split_pack - split packing inequality
+*
+* Let there be given a packing inequality in canonical form:
+*
+* sum t[j] <= 1, (1)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable.
+* And let J = J1 U J2 is a partition of the set of literals. Then the
+* inequality (1) is obviously equivalent to the following two packing
+* inequalities:
+*
+* sum t[j] <= y <--> sum t[j] + (1 - y) <= 1, (2)
+* j in J1 j in J1
+*
+* sum t[j] <= 1 - y <--> sum t[j] + y <= 1, (3)
+* j in J2 j in J2
+*
+* where y is a new binary variable added to the transformed problem.
+*
+* Assuming that the specified row is a packing inequality (1), this
+* routine constructs the set J1 by including there first nlit literals
+* (terms) from the specified row, and the set J2 = J \ J1. Then the
+* routine creates a new row, which corresponds to inequality (2), and
+* replaces the specified row with inequality (3). */
+
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nlit)
+{ NPPROW *rrr;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int k;
+ /* original row should be packing inequality (1) */
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* and nlit should be less than the number of literals (terms)
+ in the original row */
+ xassert(0 < nlit && nlit < npp_row_nnz(npp, row));
+ /* create new row corresponding to inequality (2) */
+ rrr = npp_add_row(npp);
+ rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+ /* move first nlit literals (terms) from the original row to the
+ new row; the original row becomes inequality (3) */
+ for (k = 1; k <= nlit; k++)
+ { aij = row->ptr;
+ xassert(aij != NULL);
+ /* add literal to the new row */
+ npp_add_aij(npp, rrr, aij->col, aij->val);
+ /* correct rhs */
+ if (aij->val < 0.0)
+ rrr->ub -= 1.0, row->ub += 1.0;
+ /* remove literal from the original row */
+ npp_del_aij(npp, aij);
+ }
+ /* create new binary variable y */
+ col = npp_add_col(npp);
+ col->is_int = 1, col->lb = 0.0, col->ub = 1.0;
+ /* include literal (1 - y) in the new row */
+ npp_add_aij(npp, rrr, col, -1.0);
+ rrr->ub -= 1.0;
+ /* include literal y in the original row */
+ npp_add_aij(npp, row, col, +1.0);
+ return rrr;
+}
+
+/***********************************************************************
+* npp_sat_encode_pack - encode packing inequality
+*
+* Given a packing inequality in canonical form:
+*
+* sum t[j] <= 1, (1)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable,
+* this routine translates it to CNF by replacing it with the following
+* equivalent set of edge packing inequalities:
+*
+* t[j] + t[k] <= 1 for all j, k in J, j != k. (2)
+*
+* Then the routine transforms each edge packing inequality (2) to
+* corresponding covering inequality (that encodes two-literal clause)
+* by multiplying both its part by -1:
+*
+* - t[j] - t[k] >= -1 <--> (1 - t[j]) + (1 - t[k]) >= 1. (3)
+*
+* On exit the routine removes the original row from the problem. */
+
+void npp_sat_encode_pack(NPP *npp, NPPROW *row)
+{ NPPROW *rrr;
+ NPPAIJ *aij, *aik;
+ /* original row should be packing inequality (1) */
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* create equivalent system of covering inequalities (3) */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { /* due to symmetry only one of inequalities t[j] + t[k] <= 1
+ and t[k] <= t[j] <= 1 can be considered */
+ for (aik = aij->r_next; aik != NULL; aik = aik->r_next)
+ { /* create edge packing inequality (2) */
+ rrr = npp_add_row(npp);
+ rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+ npp_add_aij(npp, rrr, aij->col, aij->val);
+ if (aij->val < 0.0)
+ rrr->ub -= 1.0;
+ npp_add_aij(npp, rrr, aik->col, aik->val);
+ if (aik->val < 0.0)
+ rrr->ub -= 1.0;
+ /* and transform it to covering inequality (3) */
+ npp_sat_reverse_row(npp, rrr);
+ xassert(npp_sat_is_cover_ineq(npp, rrr) == 1);
+ }
+ }
+ /* remove the original row from the problem */
+ npp_del_row(npp, row);
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum2 - encode 2-bit summation
+*
+* Given a set containing two literals x and y this routine encodes
+* the equality
+*
+* x + y = s + 2 * c, (1)
+*
+* where
+*
+* s = (x + y) % 2 (2)
+*
+* is a binary variable modeling the low sum bit, and
+*
+* c = (x + y) / 2 (3)
+*
+* is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed)
+{ NPPROW *row;
+ int x, y, s, c;
+ /* the set should contain exactly two literals */
+ xassert(set != NULL);
+ xassert(set->next != NULL);
+ xassert(set->next->next == NULL);
+ sed->x = set->lit;
+ xassert(sed->x.neg == 0 || sed->x.neg == 1);
+ sed->y = set->next->lit;
+ xassert(sed->y.neg == 0 || sed->y.neg == 1);
+ sed->z.col = NULL, sed->z.neg = 0;
+ /* perform encoding s = (x + y) % 2 */
+ sed->s = npp_add_col(npp);
+ sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (s = 0; s <= 1; s++)
+ { if ((x + y) % 2 != s)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (s == 0)
+ npp_add_aij(npp, row, sed->s, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->s, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ /* perform encoding c = (x + y) / 2 */
+ sed->c = npp_add_col(npp);
+ sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (c = 0; c <= 1; c++)
+ { if ((x + y) / 2 != c)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (c == 0)
+ npp_add_aij(npp, row, sed->c, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->c, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum3 - encode 3-bit summation
+*
+* Given a set containing at least three literals this routine chooses
+* some literals x, y, z from that set and encodes the equality
+*
+* x + y + z = s + 2 * c, (1)
+*
+* where
+*
+* s = (x + y + z) % 2 (2)
+*
+* is a binary variable modeling the low sum bit, and
+*
+* c = (x + y + z) / 2 (3)
+*
+* is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed)
+{ NPPROW *row;
+ int x, y, z, s, c;
+ /* the set should contain at least three literals */
+ xassert(set != NULL);
+ xassert(set->next != NULL);
+ xassert(set->next->next != NULL);
+ sed->x = set->lit;
+ xassert(sed->x.neg == 0 || sed->x.neg == 1);
+ sed->y = set->next->lit;
+ xassert(sed->y.neg == 0 || sed->y.neg == 1);
+ sed->z = set->next->next->lit;
+ xassert(sed->z.neg == 0 || sed->z.neg == 1);
+ /* perform encoding s = (x + y + z) % 2 */
+ sed->s = npp_add_col(npp);
+ sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (z = 0; z <= 1; z++)
+ { for (s = 0; s <= 1; s++)
+ { if ((x + y + z) % 2 != s)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (z == sed->z.neg)
+ npp_add_aij(npp, row, sed->z.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->z.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (s == 0)
+ npp_add_aij(npp, row, sed->s, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->s, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* perform encoding c = (x + y + z) / 2 */
+ sed->c = npp_add_col(npp);
+ sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (z = 0; z <= 1; z++)
+ { for (c = 0; c <= 1; c++)
+ { if ((x + y + z) / 2 != c)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (z == sed->z.neg)
+ npp_add_aij(npp, row, sed->z.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->z.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (c == 0)
+ npp_add_aij(npp, row, sed->c, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->c, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum_ax - encode linear combination of 0-1 variables
+*
+* PURPOSE
+*
+* Given a linear combination of binary variables:
+*
+* sum a[j] x[j], (1)
+* j
+*
+* which is the linear form of the specified row, this routine encodes
+* (i.e. translates to CNF) the following equality:
+*
+* n
+* sum |a[j]| t[j] = sum 2**(k-1) * y[k], (2)
+* j k=1
+*
+* where t[j] = x[j] (if a[j] > 0) or t[j] = 1 - x[j] (if a[j] < 0),
+* and y[k] is either t[j] or a new literal created by the routine or
+* a constant zero. Note that the sum in the right-hand side of (2) can
+* be thought as a n-bit representation of the sum in the left-hand
+* side, which is a non-negative integer number.
+*
+* ALGORITHM
+*
+* First, the number of bits, n, sufficient to represent any value in
+* the left-hand side of (2) is determined. Obviously, n is the number
+* of bits sufficient to represent the sum (sum |a[j]|).
+*
+* Let
+*
+* n
+* |a[j]| = sum 2**(k-1) b[j,k], (3)
+* k=1
+*
+* where b[j,k] is k-th bit in a n-bit representation of |a[j]|. Then
+*
+* m n
+* sum |a[j]| * t[j] = sum 2**(k-1) sum b[j,k] * t[j]. (4)
+* j k=1 j=1
+*
+* Introducing the set
+*
+* J[k] = { j : b[j,k] = 1 } (5)
+*
+* allows rewriting (4) as follows:
+*
+* n
+* sum |a[j]| * t[j] = sum 2**(k-1) sum t[j]. (6)
+* j k=1 j in J[k]
+*
+* Thus, our goal is to provide |J[k]| <= 1 for all k, in which case
+* we will have the representation (1).
+*
+* Let |J[k]| = 2, i.e. J[k] has exactly two literals u and v. In this
+* case we can apply the following transformation:
+*
+* u + v = s + 2 * c, (7)
+*
+* where s and c are, respectively, low (sum) and high (carry) bits of
+* the sum of two bits. This allows to replace two literals u and v in
+* J[k] by one literal s, and carry out literal c to J[k+1].
+*
+* If |J[k]| >= 3, i.e. J[k] has at least three literals u, v, and w,
+* we can apply the following transformation:
+*
+* u + v + w = s + 2 * c. (8)
+*
+* Again, literal s replaces literals u, v, and w in J[k], and literal
+* c goes into J[k+1].
+*
+* On exit the routine stores each literal from J[k] in element y[k],
+* 1 <= k <= n. If J[k] is empty, y[k] is set to constant false.
+*
+* RETURNS
+*
+* The routine returns n, the number of literals in the right-hand side
+* of (2), 0 <= n <= NBIT_MAX. If the sum (sum |a[j]|) is too large, so
+* more than NBIT_MAX (= 31) literals are needed to encode the original
+* linear combination, the routine returns a negative value. */
+
+#define NBIT_MAX 31
+/* maximal number of literals in the right hand-side of (2) */
+
+static NPPLSE *remove_lse(NPP *npp, NPPLSE *set, NPPCOL *col)
+{ /* remove specified literal from specified literal set */
+ NPPLSE *lse, *prev = NULL;
+ for (lse = set; lse != NULL; prev = lse, lse = lse->next)
+ if (lse->lit.col == col) break;
+ xassert(lse != NULL);
+ if (prev == NULL)
+ set = lse->next;
+ else
+ prev->next = lse->next;
+ dmp_free_atom(npp->pool, lse, sizeof(NPPLSE));
+ return set;
+}
+
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[])
+{ NPPAIJ *aij;
+ NPPLSE *set[1+NBIT_MAX], *lse;
+ NPPSED sed;
+ int k, n, temp;
+ double sum;
+ /* compute the sum (sum |a[j]|) */
+ sum = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ sum += fabs(aij->val);
+ /* determine n, the number of bits in the sum */
+ temp = (int)sum;
+ if ((double)temp != sum)
+ return -1; /* integer arithmetic error */
+ for (n = 0; temp > 0; n++, temp >>= 1);
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* build initial sets J[k], 1 <= k <= n; see (5) */
+ /* set[k] is a pointer to the list of literals in J[k] */
+ for (k = 1; k <= n; k++)
+ set[k] = NULL;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { temp = (int)fabs(aij->val);
+ xassert((int)temp == fabs(aij->val));
+ for (k = 1; temp > 0; k++, temp >>= 1)
+ { if (temp & 1)
+ { xassert(k <= n);
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = aij->col;
+ lse->lit.neg = (aij->val > 0.0 ? 0 : 1);
+ lse->next = set[k];
+ set[k] = lse;
+ }
+ }
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* reduce J[k] and set y[k] */
+ for (;;)
+ { if (set[k] == NULL)
+ { /* J[k] is empty */
+ /* set y[k] to constant false */
+ y[k].col = NULL, y[k].neg = 0;
+ break;
+ }
+ if (set[k]->next == NULL)
+ { /* J[k] contains one literal */
+ /* set y[k] to that literal */
+ y[k] = set[k]->lit;
+ dmp_free_atom(npp->pool, set[k], sizeof(NPPLSE));
+ break;
+ }
+ if (set[k]->next->next == NULL)
+ { /* J[k] contains two literals */
+ /* apply transformation (7) */
+ npp_sat_encode_sum2(npp, set[k], &sed);
+ }
+ else
+ { /* J[k] contains at least three literals */
+ /* apply transformation (8) */
+ npp_sat_encode_sum3(npp, set[k], &sed);
+ /* remove third literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.z.col);
+ }
+ /* remove second literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.y.col);
+ /* remove first literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.x.col);
+ /* include new literal s to set[k] */
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = sed.s, lse->lit.neg = 0;
+ lse->next = set[k];
+ set[k] = lse;
+ /* include new literal c to set[k+1] */
+ xassert(k < n); /* FIXME: can "overflow" happen? */
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = sed.c, lse->lit.neg = 0;
+ lse->next = set[k+1];
+ set[k+1] = lse;
+ }
+ }
+ return n;
+}
+
+/***********************************************************************
+* npp_sat_normalize_clause - normalize clause
+*
+* This routine normalizes the specified clause, which is a disjunction
+* of literals, by replacing multiple literals, which refer to the same
+* binary variable, with a single literal.
+*
+* On exit the routine returns the number of literals in the resulting
+* clause. However, if the specified clause includes both a literal and
+* its negation, the routine returns a negative value meaning that the
+* clause is equivalent to the value true. */
+
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[])
+{ int j, k, new_size;
+ xassert(npp == npp);
+ xassert(size >= 0);
+ new_size = 0;
+ for (k = 1; k <= size; k++)
+ { for (j = 1; j <= new_size; j++)
+ { if (lit[k].col == lit[j].col)
+ { /* lit[k] refers to the same variable as lit[j], which
+ is already included in the resulting clause */
+ if (lit[k].neg == lit[j].neg)
+ { /* ignore lit[k] due to the idempotent law */
+ goto skip;
+ }
+ else
+ { /* lit[k] is NOT lit[j]; the clause is equivalent to
+ the value true */
+ return -1;
+ }
+ }
+ }
+ /* include lit[k] in the resulting clause */
+ lit[++new_size] = lit[k];
+skip: ;
+ }
+ return new_size;
+}
+
+/***********************************************************************
+* npp_sat_encode_clause - translate clause to cover inequality
+*
+* Given a clause
+*
+* OR t[j], (1)
+* j in J
+*
+* where t[j] is a literal, i.e. t[j] = x[j] or t[j] = NOT x[j], this
+* routine translates it to the following equivalent cover inequality,
+* which is added to the transformed problem:
+*
+* sum t[j] >= 1, (2)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j].
+*
+* If necessary, the clause should be normalized before a call to this
+* routine. */
+
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[])
+{ NPPROW *row;
+ int k;
+ xassert(size >= 1);
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ for (k = 1; k <= size; k++)
+ { xassert(lit[k].col != NULL);
+ if (lit[k].neg == 0)
+ npp_add_aij(npp, row, lit[k].col, +1.0);
+ else if (lit[k].neg == 1)
+ { npp_add_aij(npp, row, lit[k].col, -1.0);
+ row->lb -= 1.0;
+ }
+ else
+ xassert(lit != lit);
+ }
+ return row;
+}
+
+/***********************************************************************
+* npp_sat_encode_geq - encode "not less than" constraint
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint:
+*
+* n
+* sum 2**(k-1) * y[k] >= b, (1)
+* k=1
+*
+* where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+* or constant false (zero), b is a given lower bound.
+*
+* ALGORITHM
+*
+* If b < 0, the constraint is redundant, so assume that b >= 0. Let
+*
+* n
+* b = sum 2**(k-1) b[k], (2)
+* k=1
+*
+* where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+* therefore cannot be represented in the form (2), the constraint (1)
+* is infeasible.) In this case the condition (1) is equivalent to the
+* following condition:
+*
+* y[n] y[n-1] ... y[2] y[1] >= b[n] b[n-1] ... b[2] b[1], (3)
+*
+* where ">=" is understood lexicographically.
+*
+* Algorithmically the condition (3) can be tested as follows:
+*
+* for (k = n; k >= 1; k--)
+* { if (y[k] < b[k])
+* y is less than b;
+* if (y[k] > b[k])
+* y is greater than b;
+* }
+* y is equal to b;
+*
+* Thus, y is less than b iff there exists k, 1 <= k <= n, for which
+* the following condition is satisfied:
+*
+* y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] < b[k]. (4)
+*
+* Negating the condition (4) we have that y is not less than b iff for
+* all k, 1 <= k <= n, the following condition is satisfied:
+*
+* y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] >= b[k]. (5)
+*
+* Note that if b[k] = 0, the literal y[k] >= b[k] is always true, in
+* which case the entire clause (5) is true and can be omitted.
+*
+* RETURNS
+*
+* Normally the routine returns zero. However, if the constraint (1) is
+* infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs)
+{ NPPLIT lit[1+NBIT_MAX];
+ int j, k, size, temp, b[1+NBIT_MAX];
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* if the constraint (1) is redundant, do nothing */
+ if (rhs < 0)
+ return 0;
+ /* determine binary digits of b according to (2) */
+ for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+ b[k] = temp & 1;
+ if (temp != 0)
+ { /* b >= 2**n; the constraint (1) is infeasible */
+ return 1;
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* build the clause (5) for current k */
+ size = 0; /* clause size = number of literals */
+ /* add literal y[k] >= b[k] */
+ if (b[k] == 0)
+ { /* b[k] = 0 -> the literal is true */
+ goto skip;
+ }
+ else if (y[k].col == NULL)
+ { /* y[k] = 0, b[k] = 1 -> the literal is false */
+ xassert(y[k].neg == 0);
+ }
+ else
+ { /* add literal y[k] = 1 */
+ lit[++size] = y[k];
+ }
+ for (j = k+1; j <= n; j++)
+ { /* add literal y[j] != b[j] */
+ if (y[j].col == NULL)
+ { xassert(y[j].neg == 0);
+ if (b[j] == 0)
+ { /* y[j] = 0, b[j] = 0 -> the literal is false */
+ continue;
+ }
+ else
+ { /* y[j] = 0, b[j] = 1 -> the literal is true */
+ goto skip;
+ }
+ }
+ else
+ { lit[++size] = y[j];
+ if (b[j] != 0)
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ }
+ /* normalize the clause */
+ size = npp_sat_normalize_clause(npp, size, lit);
+ if (size < 0)
+ { /* the clause is equivalent to the value true */
+ goto skip;
+ }
+ if (size == 0)
+ { /* the clause is equivalent to the value false; this means
+ that the constraint (1) is infeasible */
+ return 2;
+ }
+ /* translate the clause to corresponding cover inequality */
+ npp_sat_encode_clause(npp, size, lit);
+skip: ;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_leq - encode "not greater than" constraint
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint:
+*
+* n
+* sum 2**(k-1) * y[k] <= b, (1)
+* k=1
+*
+* where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+* or constant false (zero), b is a given upper bound.
+*
+* ALGORITHM
+*
+* If b < 0, the constraint is infeasible, so assume that b >= 0. Let
+*
+* n
+* b = sum 2**(k-1) b[k], (2)
+* k=1
+*
+* where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+* therefore cannot be represented in the form (2), the constraint (1)
+* is redundant.) In this case the condition (1) is equivalent to the
+* following condition:
+*
+* y[n] y[n-1] ... y[2] y[1] <= b[n] b[n-1] ... b[2] b[1], (3)
+*
+* where "<=" is understood lexicographically.
+*
+* Algorithmically the condition (3) can be tested as follows:
+*
+* for (k = n; k >= 1; k--)
+* { if (y[k] < b[k])
+* y is less than b;
+* if (y[k] > b[k])
+* y is greater than b;
+* }
+* y is equal to b;
+*
+* Thus, y is greater than b iff there exists k, 1 <= k <= n, for which
+* the following condition is satisfied:
+*
+* y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] > b[k]. (4)
+*
+* Negating the condition (4) we have that y is not greater than b iff
+* for all k, 1 <= k <= n, the following condition is satisfied:
+*
+* y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] <= b[k]. (5)
+*
+* Note that if b[k] = 1, the literal y[k] <= b[k] is always true, in
+* which case the entire clause (5) is true and can be omitted.
+*
+* RETURNS
+*
+* Normally the routine returns zero. However, if the constraint (1) is
+* infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs)
+{ NPPLIT lit[1+NBIT_MAX];
+ int j, k, size, temp, b[1+NBIT_MAX];
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* check if the constraint (1) is infeasible */
+ if (rhs < 0)
+ return 1;
+ /* determine binary digits of b according to (2) */
+ for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+ b[k] = temp & 1;
+ if (temp != 0)
+ { /* b >= 2**n; the constraint (1) is redundant */
+ return 0;
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* build the clause (5) for current k */
+ size = 0; /* clause size = number of literals */
+ /* add literal y[k] <= b[k] */
+ if (b[k] == 1)
+ { /* b[k] = 1 -> the literal is true */
+ goto skip;
+ }
+ else if (y[k].col == NULL)
+ { /* y[k] = 0, b[k] = 0 -> the literal is true */
+ xassert(y[k].neg == 0);
+ goto skip;
+ }
+ else
+ { /* add literal y[k] = 0 */
+ lit[++size] = y[k];
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ for (j = k+1; j <= n; j++)
+ { /* add literal y[j] != b[j] */
+ if (y[j].col == NULL)
+ { xassert(y[j].neg == 0);
+ if (b[j] == 0)
+ { /* y[j] = 0, b[j] = 0 -> the literal is false */
+ continue;
+ }
+ else
+ { /* y[j] = 0, b[j] = 1 -> the literal is true */
+ goto skip;
+ }
+ }
+ else
+ { lit[++size] = y[j];
+ if (b[j] != 0)
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ }
+ /* normalize the clause */
+ size = npp_sat_normalize_clause(npp, size, lit);
+ if (size < 0)
+ { /* the clause is equivalent to the value true */
+ goto skip;
+ }
+ if (size == 0)
+ { /* the clause is equivalent to the value false; this means
+ that the constraint (1) is infeasible */
+ return 2;
+ }
+ /* translate the clause to corresponding cover inequality */
+ npp_sat_encode_clause(npp, size, lit);
+skip: ;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_row - encode constraint (row) of general type
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint (row):
+*
+* L <= sum a[j] x[j] <= U, (1)
+* j
+*
+* where all x[j] are binary variables.
+*
+* ALGORITHM
+*
+* First, the routine performs substitution x[j] = t[j] for j in J+
+* and x[j] = 1 - t[j] for j in J-, where J+ = { j : a[j] > 0 } and
+* J- = { j : a[j] < 0 }. This gives:
+*
+* L <= sum a[j] t[j] + sum a[j] (1 - t[j]) <= U ==>
+* j in J+ j in J-
+*
+* L' <= sum |a[j]| t[j] <= U', (2)
+* j
+*
+* where
+*
+* L' = L - sum a[j], U' = U - sum a[j]. (3)
+* j in J- j in J-
+*
+* (Actually only new bounds L' and U' are computed.)
+*
+* Then the routine translates to CNF the following equality:
+*
+* n
+* sum |a[j]| t[j] = sum 2**(k-1) * y[k], (4)
+* j k=1
+*
+* where y[k] is either some t[j] or a new literal or a constant zero
+* (see the routine npp_sat_encode_sum_ax).
+*
+* Finally, the routine translates to CNF the following conditions:
+*
+* n
+* sum 2**(k-1) * y[k] >= L' (5)
+* k=1
+*
+* and
+*
+* n
+* sum 2**(k-1) * y[k] <= U' (6)
+* k=1
+*
+* (see the routines npp_sat_encode_geq and npp_sat_encode_leq).
+*
+* All resulting clauses are encoded as cover inequalities and included
+* into the transformed problem.
+*
+* Note that on exit the routine removes the specified constraint (row)
+* from the original problem.
+*
+* RETURNS
+*
+* The routine returns one of the following codes:
+*
+* 0 - translation was successful;
+* 1 - constraint (1) was found infeasible;
+* 2 - integer arithmetic error occured. */
+
+int npp_sat_encode_row(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ NPPLIT y[1+NBIT_MAX];
+ int n, rhs;
+ double lb, ub;
+ /* the row should not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* compute new bounds L' and U' (3) */
+ lb = row->lb;
+ ub = row->ub;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val < 0.0)
+ { if (lb != -DBL_MAX)
+ lb -= aij->val;
+ if (ub != -DBL_MAX)
+ ub -= aij->val;
+ }
+ }
+ /* encode the equality (4) */
+ n = npp_sat_encode_sum_ax(npp, row, y);
+ if (n < 0)
+ return 2; /* integer arithmetic error */
+ /* encode the condition (5) */
+ if (lb != -DBL_MAX)
+ { rhs = (int)lb;
+ if ((double)rhs != lb)
+ return 2; /* integer arithmetic error */
+ if (npp_sat_encode_geq(npp, n, y, rhs) != 0)
+ return 1; /* original constraint is infeasible */
+ }
+ /* encode the condition (6) */
+ if (ub != +DBL_MAX)
+ { rhs = (int)ub;
+ if ((double)rhs != ub)
+ return 2; /* integer arithmetic error */
+ if (npp_sat_encode_leq(npp, n, y, rhs) != 0)
+ return 1; /* original constraint is infeasible */
+ }
+ /* remove the specified row from the problem */
+ npp_del_row(npp, row);
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_prob - encode 0-1 feasibility problem
+*
+* This routine translates the specified 0-1 feasibility problem to an
+* equivalent SAT-CNF problem.
+*
+* N.B. Currently this is a very crude implementation.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ERANGE integer overflow occured. */
+
+int npp_sat_encode_prob(NPP *npp)
+{ NPPROW *row, *next_row, *prev_row;
+ NPPCOL *col, *next_col;
+ int cover = 0, pack = 0, partn = 0, ret;
+ /* process and remove free rows */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ npp_sat_free_row(npp, row);
+ }
+ /* process and remove fixed columns */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb == col->ub)
+ xassert(npp_sat_fixed_col(npp, col) == 0);
+ }
+ /* only binary variables should remain */
+ for (col = npp->c_head; col != NULL; col = col->next)
+ xassert(col->is_int && col->lb == 0.0 && col->ub == 1.0);
+ /* new rows may be added to the end of the row list, so we walk
+ from the end to beginning of the list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* process special cases */
+ ret = npp_sat_is_cover_ineq(npp, row);
+ if (ret != 0)
+ { /* row is covering inequality */
+ cover++;
+ /* since it already encodes a clause, just transform it to
+ canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_cover_ineq(npp, row);
+ }
+ xassert(ret == 1);
+ continue;
+ }
+ ret = npp_sat_is_partn_eq(npp, row);
+ if (ret != 0)
+ { /* row is partitioning equality */
+ NPPROW *cov;
+ NPPAIJ *aij;
+ partn++;
+ /* transform it to canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_partn_eq(npp, row);
+ }
+ xassert(ret == 1);
+ /* and split it into covering and packing inequalities,
+ both in canonical forms */
+ cov = npp_add_row(npp);
+ cov->lb = row->lb, cov->ub = +DBL_MAX;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, cov, aij->col, aij->val);
+ xassert(npp_sat_is_cover_ineq(npp, cov) == 1);
+ /* the cover inequality already encodes a clause and do
+ not need any further processing */
+ row->lb = -DBL_MAX;
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* the packing inequality will be processed below */
+ pack--;
+ }
+ ret = npp_sat_is_pack_ineq(npp, row);
+ if (ret != 0)
+ { /* row is packing inequality */
+ NPPROW *rrr;
+ int nlit, desired_nlit = 4;
+ pack++;
+ /* transform it to canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_pack_ineq(npp, row);
+ }
+ xassert(ret == 1);
+ /* process the packing inequality */
+ for (;;)
+ { /* determine the number of literals in the remaining
+ inequality */
+ nlit = npp_row_nnz(npp, row);
+ if (nlit <= desired_nlit)
+ break;
+ /* split the current inequality into one having not more
+ than desired_nlit literals and remaining one */
+ rrr = npp_sat_split_pack(npp, row, desired_nlit-1);
+ /* translate the former inequality to CNF and remove it
+ from the original problem */
+ npp_sat_encode_pack(npp, rrr);
+ }
+ /* translate the remaining inequality to CNF and remove it
+ from the original problem */
+ npp_sat_encode_pack(npp, row);
+ continue;
+ }
+ /* translate row of general type to CNF and remove it from the
+ original problem */
+ ret = npp_sat_encode_row(npp, row);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ ret = GLP_ENOPFS;
+ else if (ret == 2)
+ ret = GLP_ERANGE;
+ else
+ xassert(ret != ret);
+ if (ret != 0)
+ goto done;
+ }
+ ret = 0;
+ if (cover != 0)
+ xprintf("%d covering inequalities\n", cover);
+ if (pack != 0)
+ xprintf("%d packing inequalities\n", pack);
+ if (partn != 0)
+ xprintf("%d partitioning equalities\n", partn);
+done: return ret;
+}
+
+/* eof */